Skip to content

Commit 963e35d

Browse files
authored
Merge pull request #1 from dhoomakethu/first-cut
First cut
2 parents fc2e287 + e560430 commit 963e35d

File tree

15 files changed

+3188
-0
lines changed

15 files changed

+3188
-0
lines changed

poetry.lock

Lines changed: 629 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pymodbus/repl/README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Pymodbus REPL (Client/Server)
2+
3+
REPL implementation for client and server.
4+
5+
## Pymodbus Client
6+
Refer [REPL Client](./client/README.rst)
7+
8+
## Pymodbus Server
9+
Refer [REPL Server](./server/README.rst)

pymodbus/repl/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Pymodbus REPL Module."""

pymodbus/repl/client/README.rst

Lines changed: 312 additions & 0 deletions
Large diffs are not rendered by default.

pymodbus/repl/client/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Repl client."""

pymodbus/repl/client/completer.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
"""Command Completion for pymodbus REPL."""
2+
from prompt_toolkit.application.current import get_app
3+
4+
# pylint: disable=missing-type-doc
5+
from prompt_toolkit.completion import Completer, Completion
6+
from prompt_toolkit.filters import Condition
7+
from prompt_toolkit.styles import Style
8+
9+
from pymodbus.repl.client.helper import get_commands
10+
11+
12+
@Condition
13+
def has_selected_completion():
14+
"""Check for selected completion."""
15+
complete_state = get_app().current_buffer.complete_state
16+
return complete_state is not None and complete_state.current_completion is not None
17+
18+
19+
style = Style.from_dict(
20+
{
21+
"completion-menu.completion": "bg:#008888 #ffffff",
22+
"completion-menu.completion.current": "bg:#00aaaa #000000",
23+
"scrollbar.background": "bg:#88aaaa",
24+
"scrollbar.button": "bg:#222222",
25+
}
26+
)
27+
28+
29+
class CmdCompleter(Completer):
30+
"""Completer for Pymodbus REPL."""
31+
32+
def __init__(self, client=None, commands=None, ignore_case=True):
33+
"""Initialize.
34+
35+
:param client: Modbus Client
36+
:param commands: Commands to be added for Completion (list)
37+
:param ignore_case: Ignore Case while looking up for commands
38+
"""
39+
self._commands = commands or get_commands(client)
40+
self._commands["help"] = ""
41+
self._command_names = self._commands.keys()
42+
self.ignore_case = ignore_case
43+
44+
@property
45+
def commands(self):
46+
"""Return commands."""
47+
return self._commands
48+
49+
@property
50+
def command_names(self):
51+
"""Return command names."""
52+
return self._commands.keys()
53+
54+
def completing_command(self, words, word_before_cursor):
55+
"""Determine if we are dealing with supported command.
56+
57+
:param words: Input text broken in to word tokens.
58+
:param word_before_cursor: The current word before the cursor, \
59+
which might be one or more blank spaces.
60+
:return:
61+
"""
62+
return len(words) == 1 and len(word_before_cursor)
63+
64+
def completing_arg(self, words, word_before_cursor):
65+
"""Determine if we are currently completing an argument.
66+
67+
:param words: The input text broken into word tokens.
68+
:param word_before_cursor: The current word before the cursor, \
69+
which might be one or more blank spaces.
70+
:return: Specifies whether we are currently completing an arg.
71+
"""
72+
return len(words) > 1 and len(word_before_cursor)
73+
74+
def arg_completions(self, words, _word_before_cursor):
75+
"""Generate arguments completions based on the input."""
76+
cmd = words[0].strip()
77+
cmd = self._commands.get(cmd, None)
78+
return cmd if cmd else None
79+
80+
def _get_completions(self, word, word_before_cursor):
81+
"""Get completions."""
82+
if self.ignore_case:
83+
word_before_cursor = word_before_cursor.lower()
84+
return self.word_matches(word, word_before_cursor)
85+
86+
def word_matches(self, word, word_before_cursor):
87+
"""Match the word and word before cursor.
88+
89+
:param word: The input text broken into word tokens.
90+
:param word_before_cursor: The current word before the cursor, \
91+
which might be one or more blank spaces.
92+
:return: True if matched.
93+
94+
"""
95+
if self.ignore_case:
96+
word = word.lower()
97+
return word.startswith(word_before_cursor)
98+
99+
def get_completions(self, document, complete_event):
100+
"""Get completions for the current scope.
101+
102+
:param document: An instance of `prompt_toolkit.Document`.
103+
:param complete_event: (Unused).
104+
:return: Yields an instance of `prompt_toolkit.completion.Completion`.
105+
"""
106+
word_before_cursor = document.get_word_before_cursor(WORD=True)
107+
text = document.text_before_cursor.lstrip()
108+
words = document.text.strip().split()
109+
meta = None
110+
commands = []
111+
if not words:
112+
# yield commands
113+
pass
114+
if self.completing_command(words, word_before_cursor):
115+
commands = self._command_names
116+
c_meta = {
117+
k: v.help_text if not isinstance(v, str) else v
118+
for k, v in self._commands.items()
119+
}
120+
meta = lambda x: ( # pylint: disable=unnecessary-lambda-assignment
121+
x,
122+
c_meta.get(x, ""),
123+
)
124+
else:
125+
if not list(
126+
filter(lambda cmd: any(x == cmd for x in words), self._command_names)
127+
):
128+
# yield commands
129+
pass
130+
131+
if " " in text:
132+
command = self.arg_completions(words, word_before_cursor)
133+
commands = list(command.get_completion())
134+
commands = list(
135+
filter(lambda cmd: not (any(cmd in x for x in words)), commands)
136+
)
137+
meta = command.get_meta
138+
for command in commands:
139+
if self._get_completions(command, word_before_cursor):
140+
_, display_meta = meta(command) if meta else ("", "")
141+
yield Completion(
142+
command, -len(word_before_cursor), display_meta=display_meta
143+
)

0 commit comments

Comments
 (0)