suplemon-editor 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- suplemon/__init__.py +0 -0
- suplemon/__main__.py +3 -0
- suplemon/cli.py +65 -0
- suplemon/config/defaults.json +153 -0
- suplemon/config/keymap.json +63 -0
- suplemon/config.py +324 -0
- suplemon/cursor.py +135 -0
- suplemon/editor.py +568 -0
- suplemon/file.py +193 -0
- suplemon/help.py +327 -0
- suplemon/helpers.py +104 -0
- suplemon/hex2xterm.py +23 -0
- suplemon/key_mappings.py +239 -0
- suplemon/lexer.py +88 -0
- suplemon/line.py +51 -0
- suplemon/linelight/__init__.py +0 -0
- suplemon/linelight/color_map.py +9 -0
- suplemon/linelight/css.py +21 -0
- suplemon/linelight/diff.py +17 -0
- suplemon/linelight/html.py +19 -0
- suplemon/linelight/js.py +21 -0
- suplemon/linelight/json.py +15 -0
- suplemon/linelight/lua.py +10 -0
- suplemon/linelight/md.py +19 -0
- suplemon/linelight/php.py +27 -0
- suplemon/linelight/py.py +27 -0
- suplemon/logger.py +90 -0
- suplemon/main.py +771 -0
- suplemon/module_loader.py +98 -0
- suplemon/modules/application_state.py +84 -0
- suplemon/modules/autocomplete.py +114 -0
- suplemon/modules/autodocstring.py +142 -0
- suplemon/modules/battery.py +118 -0
- suplemon/modules/bulk_delete.py +75 -0
- suplemon/modules/clock.py +22 -0
- suplemon/modules/comment.py +59 -0
- suplemon/modules/config.py +20 -0
- suplemon/modules/date.py +22 -0
- suplemon/modules/diff.py +42 -0
- suplemon/modules/eval.py +43 -0
- suplemon/modules/hostname.py +34 -0
- suplemon/modules/input_test.py +23 -0
- suplemon/modules/keymap.py +20 -0
- suplemon/modules/linter.py +274 -0
- suplemon/modules/lower.py +21 -0
- suplemon/modules/lstrip.py +20 -0
- suplemon/modules/paste.py +49 -0
- suplemon/modules/reload.py +16 -0
- suplemon/modules/replace_all.py +23 -0
- suplemon/modules/reverse.py +22 -0
- suplemon/modules/rstrip.py +19 -0
- suplemon/modules/save.py +16 -0
- suplemon/modules/save_all.py +19 -0
- suplemon/modules/sort_lines.py +41 -0
- suplemon/modules/strip.py +19 -0
- suplemon/modules/system_clipboard.py +121 -0
- suplemon/modules/tabstospaces.py +18 -0
- suplemon/modules/toggle_whitespace.py +18 -0
- suplemon/modules/upper.py +21 -0
- suplemon/prompt.py +319 -0
- suplemon/suplemon_module.py +210 -0
- suplemon/themes/8colors.tmTheme +179 -0
- suplemon/themes/monokai.tmTheme +284 -0
- suplemon/themes.py +201 -0
- suplemon/ui.py +656 -0
- suplemon/viewer.py +1004 -0
- suplemon_editor-0.3.0.dist-info/METADATA +515 -0
- suplemon_editor-0.3.0.dist-info/RECORD +72 -0
- suplemon_editor-0.3.0.dist-info/WHEEL +5 -0
- suplemon_editor-0.3.0.dist-info/entry_points.txt +3 -0
- suplemon_editor-0.3.0.dist-info/licenses/LICENSE +21 -0
- suplemon_editor-0.3.0.dist-info/top_level.txt +1 -0
suplemon/key_mappings.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# -*- encoding: utf-8
|
|
2
|
+
"""
|
|
3
|
+
This file maps ugly curses keycodes to human readable versions.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import curses
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
key_map = {
|
|
10
|
+
# Single keys
|
|
11
|
+
curses.KEY_F1: "f1", # 265
|
|
12
|
+
curses.KEY_F2: "f2", # 266
|
|
13
|
+
curses.KEY_F3: "f3", # 267
|
|
14
|
+
curses.KEY_F4: "f4", # 268
|
|
15
|
+
curses.KEY_F5: "f5", # 269
|
|
16
|
+
curses.KEY_F6: "f6", # 270
|
|
17
|
+
curses.KEY_F7: "f7", # 271
|
|
18
|
+
curses.KEY_F8: "f8", # 272
|
|
19
|
+
curses.KEY_F9: "f9", # 273
|
|
20
|
+
curses.KEY_F10: "f10", # 274
|
|
21
|
+
curses.KEY_F11: "f11", # 275
|
|
22
|
+
curses.KEY_F12: "f12", # 276
|
|
23
|
+
"KEY_F(1)": "f1",
|
|
24
|
+
"KEY_F(2)": "f2",
|
|
25
|
+
"KEY_F(3)": "f3",
|
|
26
|
+
"KEY_F(4)": "f4",
|
|
27
|
+
"KEY_F(5)": "f5",
|
|
28
|
+
"KEY_F(6)": "f6",
|
|
29
|
+
"KEY_F(7)": "f7",
|
|
30
|
+
"KEY_F(8)": "f8",
|
|
31
|
+
"KEY_F(9)": "f9",
|
|
32
|
+
"KEY_F(10)": "f10",
|
|
33
|
+
"KEY_F(11)": "f11",
|
|
34
|
+
"KEY_F(12)": "f12",
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
curses.KEY_UP: "up",
|
|
38
|
+
curses.KEY_DOWN: "down",
|
|
39
|
+
curses.KEY_LEFT: "left",
|
|
40
|
+
curses.KEY_RIGHT: "right",
|
|
41
|
+
"KEY_UP": "up",
|
|
42
|
+
"KEY_DOWN": "down",
|
|
43
|
+
"KEY_LEFT": "left",
|
|
44
|
+
"KEY_RIGHT": "right",
|
|
45
|
+
|
|
46
|
+
curses.KEY_ENTER: "enter",
|
|
47
|
+
"KEY_ENTER": "enter",
|
|
48
|
+
"\n": "enter",
|
|
49
|
+
"^J": "enter",
|
|
50
|
+
343: "shift+enter",
|
|
51
|
+
|
|
52
|
+
curses.KEY_BACKSPACE: "backspace",
|
|
53
|
+
"KEY_BACKSPACE": "backspace",
|
|
54
|
+
"^?": "backspace",
|
|
55
|
+
|
|
56
|
+
curses.KEY_DC: "delete",
|
|
57
|
+
curses.KEY_HOME: "home",
|
|
58
|
+
curses.KEY_END: "end",
|
|
59
|
+
curses.KEY_PPAGE: "pageup",
|
|
60
|
+
curses.KEY_NPAGE: "pagedown",
|
|
61
|
+
"KEY_DC": "delete",
|
|
62
|
+
"KEY_HOME": "home",
|
|
63
|
+
"KEY_END": "end",
|
|
64
|
+
"KEY_PPAGE": "pageup",
|
|
65
|
+
"KEY_NPAGE": "pagedown",
|
|
66
|
+
|
|
67
|
+
curses.KEY_IC: "insert",
|
|
68
|
+
"KEY_IC": "insert",
|
|
69
|
+
331: "insert",
|
|
70
|
+
"\t": "tab",
|
|
71
|
+
"^I": "tab",
|
|
72
|
+
"^[": "escape",
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# Control
|
|
76
|
+
"^A": "ctrl+a",
|
|
77
|
+
"^B": "ctrl+b",
|
|
78
|
+
"^C": "ctrl+c",
|
|
79
|
+
"^D": "ctrl+d",
|
|
80
|
+
"^E": "ctrl+e",
|
|
81
|
+
"^F": "ctrl+f",
|
|
82
|
+
"^G": "ctrl+g",
|
|
83
|
+
"^H": "ctrl+h",
|
|
84
|
+
# "^I": "ctrl+i", # Conflicts with 'tab'
|
|
85
|
+
# "^J": "ctrl+j", # Conflicts with 'enter'
|
|
86
|
+
"^K": "ctrl+k",
|
|
87
|
+
"^L": "ctrl+l",
|
|
88
|
+
# "^M": "ctrl+m", # Conflicts with 'enter'
|
|
89
|
+
"^N": "ctrl+n",
|
|
90
|
+
"^O": "ctrl+o",
|
|
91
|
+
"^P": "ctrl+p",
|
|
92
|
+
"^Q": "ctrl+q",
|
|
93
|
+
"^R": "ctrl+r",
|
|
94
|
+
"^S": "ctrl+s",
|
|
95
|
+
"^T": "ctrl+t",
|
|
96
|
+
"^U": "ctrl+u",
|
|
97
|
+
"^V": "ctrl+v",
|
|
98
|
+
"^W": "ctrl+w",
|
|
99
|
+
"^X": "ctrl+x",
|
|
100
|
+
"^Y": "ctrl+y",
|
|
101
|
+
"^Z": "ctrl+z", # Conflicts with suspend
|
|
102
|
+
|
|
103
|
+
"kLFT5": "ctrl+left",
|
|
104
|
+
"kRIT5": "ctrl+right",
|
|
105
|
+
"kUP5": "ctrl+up",
|
|
106
|
+
"kDN5": "ctrl+down",
|
|
107
|
+
|
|
108
|
+
"kIC5": "ctrl+insert",
|
|
109
|
+
"kDC5": "ctrl+delete",
|
|
110
|
+
"kHOM5": "ctrl+home",
|
|
111
|
+
"kEND5": "ctrl+end",
|
|
112
|
+
|
|
113
|
+
"kPRV5": "ctrl+pageup",
|
|
114
|
+
"kNXT5": "ctrl+pagedown",
|
|
115
|
+
|
|
116
|
+
"O5P": "ctrl+f1",
|
|
117
|
+
"O5Q": "ctrl+f2",
|
|
118
|
+
"O5R": "ctrl+f3",
|
|
119
|
+
"O5S": "ctrl+f4",
|
|
120
|
+
|
|
121
|
+
"KEY_F(29)": "ctrl+f5",
|
|
122
|
+
"KEY_F(30)": "ctrl+f6",
|
|
123
|
+
"KEY_F(31)": "ctrl+f7",
|
|
124
|
+
"KEY_F(32)": "ctrl+f8",
|
|
125
|
+
"KEY_F(33)": "ctrl+f9",
|
|
126
|
+
"KEY_F(34)": "ctrl+f10",
|
|
127
|
+
"KEY_F(35)": "ctrl+f11",
|
|
128
|
+
"KEY_F(36)": "ctrl+f12",
|
|
129
|
+
|
|
130
|
+
# Alt
|
|
131
|
+
"kUP3": "alt+up",
|
|
132
|
+
"kDN3": "alt+down",
|
|
133
|
+
"kLFT3": "alt+left",
|
|
134
|
+
"kRIT3": "alt+right",
|
|
135
|
+
|
|
136
|
+
"kIC3": "alt+insert",
|
|
137
|
+
"kDC3": "alt+delete",
|
|
138
|
+
"kHOM3": "alt+home",
|
|
139
|
+
"kEND3": "alt+end",
|
|
140
|
+
|
|
141
|
+
"kPRV3": "alt+pageup",
|
|
142
|
+
"kNXT3": "alt+pagedown",
|
|
143
|
+
|
|
144
|
+
"KEY_F(53)": "alt+f5",
|
|
145
|
+
"KEY_F(54)": "alt+f6",
|
|
146
|
+
"KEY_F(55)": "alt+f7",
|
|
147
|
+
"KEY_F(56)": "alt+f8",
|
|
148
|
+
"KEY_F(57)": "alt+f9",
|
|
149
|
+
"KEY_F(58)": "alt+f10",
|
|
150
|
+
"KEY_F(59)": "alt+f11",
|
|
151
|
+
"KEY_F(60)": "alt+f12",
|
|
152
|
+
|
|
153
|
+
# Shift
|
|
154
|
+
curses.KEY_SLEFT: "shift+left",
|
|
155
|
+
curses.KEY_SRIGHT: "shift+right",
|
|
156
|
+
"KEY_SLEFT": "shift+left",
|
|
157
|
+
"KEY_SRIGHT": "shift+right",
|
|
158
|
+
"KEY_SR": "shift+up",
|
|
159
|
+
"KEY_SF": "shift+down",
|
|
160
|
+
|
|
161
|
+
353: "shift+tab",
|
|
162
|
+
"KEY_BTAB": "shift+tab",
|
|
163
|
+
|
|
164
|
+
"KEY_SDC": "shift+delete",
|
|
165
|
+
"KEY_SHOME": "shift+home",
|
|
166
|
+
"KEY_SEND": "shift+end",
|
|
167
|
+
|
|
168
|
+
"KEY_SPREVIOUS": "shift+pageup",
|
|
169
|
+
"KEY_SNEXT": "shift+pagedown",
|
|
170
|
+
|
|
171
|
+
"O2P": "shift+f1",
|
|
172
|
+
"O2Q": "shift+f2",
|
|
173
|
+
"O2R": "shift+f3",
|
|
174
|
+
"O2S": "shift+f4",
|
|
175
|
+
|
|
176
|
+
# Terminals that describe shifted function keys as kf13-kf24 report these
|
|
177
|
+
# instead. shift+f5 upwards were already covered; f1-f4 were not.
|
|
178
|
+
"KEY_F(13)": "shift+f1",
|
|
179
|
+
"KEY_F(14)": "shift+f2",
|
|
180
|
+
"KEY_F(15)": "shift+f3",
|
|
181
|
+
"KEY_F(16)": "shift+f4",
|
|
182
|
+
|
|
183
|
+
"KEY_F(17)": "shift+f5",
|
|
184
|
+
"KEY_F(18)": "shift+f6",
|
|
185
|
+
"KEY_F(19)": "shift+f7",
|
|
186
|
+
"KEY_F(20)": "shift+f8",
|
|
187
|
+
"KEY_F(21)": "shift+f9",
|
|
188
|
+
"KEY_F(22)": "shift+f10",
|
|
189
|
+
"KEY_F(23)": "shift+f11",
|
|
190
|
+
"KEY_F(24)": "shift+f12",
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# Alt Gr
|
|
194
|
+
"O1P": "altgr+f1",
|
|
195
|
+
"O1Q": "altgr+f2",
|
|
196
|
+
"O1R": "altgr+f3",
|
|
197
|
+
"O1S": "altgr+f4",
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# Shift + Alt
|
|
201
|
+
"kUP4": "shift+alt+up",
|
|
202
|
+
"kDN4": "shift+alt+down",
|
|
203
|
+
"kLFT4": "shift+alt+left",
|
|
204
|
+
"kRIT4": "shift+alt+right",
|
|
205
|
+
|
|
206
|
+
"kIC4": "shift+alt+inset",
|
|
207
|
+
"kDC4": "shift+alt+delete",
|
|
208
|
+
"kHOM4": "shift+alt+home",
|
|
209
|
+
"kEND4": "shift+alt+end",
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# Control + Shift
|
|
213
|
+
"kUP6": "ctrl+shift+up",
|
|
214
|
+
"kDN6": "ctrl+shift+down",
|
|
215
|
+
"kLFT6": "ctrl+shift+left",
|
|
216
|
+
"kRIT6": "ctrl+shift+right",
|
|
217
|
+
|
|
218
|
+
"kDC6": "ctrl+shift+delete",
|
|
219
|
+
"kHOM6": "ctrl+shift+home",
|
|
220
|
+
"kEND6": "ctrl+shift+end",
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Control + Alt
|
|
224
|
+
"kUP7": "ctrl+alt+up",
|
|
225
|
+
"kDN7": "ctrl+alt+down",
|
|
226
|
+
"kLFT7": "ctrl+alt+left",
|
|
227
|
+
"kRIT7": "ctrl+alt+right",
|
|
228
|
+
|
|
229
|
+
"kPRV7": "ctrl+alt+pageup",
|
|
230
|
+
"kNXT7": "ctrl+alt+pagedown",
|
|
231
|
+
|
|
232
|
+
"kIC7": "ctrl+alt+insert",
|
|
233
|
+
"kDC7": "ctrl+alt+delete",
|
|
234
|
+
"kHOM7": "ctrl+alt+home",
|
|
235
|
+
"kEND7": "ctrl+alt+end",
|
|
236
|
+
|
|
237
|
+
# Special events
|
|
238
|
+
"KEY_RESIZE": "resize",
|
|
239
|
+
}
|
suplemon/lexer.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# -*- encoding: utf-8
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import pygments
|
|
5
|
+
import pygments.token
|
|
6
|
+
import pygments.lexers
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Lexer:
|
|
10
|
+
def __init__(self, app):
|
|
11
|
+
self.app = app
|
|
12
|
+
self.logger = logging.getLogger(__name__)
|
|
13
|
+
self.token_map = {
|
|
14
|
+
pygments.token.Text: "generic",
|
|
15
|
+
pygments.token.Generic.Strong: "string",
|
|
16
|
+
pygments.token.Generic.Subheading: "string",
|
|
17
|
+
pygments.token.Generic.Deleted: "invalid",
|
|
18
|
+
pygments.token.Punctuation: "punctuation",
|
|
19
|
+
pygments.token.Operator: "keyword",
|
|
20
|
+
pygments.token.Operator.Word: "keyword.control",
|
|
21
|
+
|
|
22
|
+
pygments.token.Comment: "comment",
|
|
23
|
+
pygments.token.Comment.Single: "comment",
|
|
24
|
+
pygments.token.Comment.Multiline: "comment",
|
|
25
|
+
|
|
26
|
+
pygments.token.Name: "entity.name",
|
|
27
|
+
pygments.token.Name.Other: "entity.name",
|
|
28
|
+
pygments.token.Name.Tag: "entity.name.tag",
|
|
29
|
+
pygments.token.Name.Class: "entity.name.class",
|
|
30
|
+
pygments.token.Name.Function: "entity.name.function",
|
|
31
|
+
pygments.token.Name.Function.Magic: "entity.name.function",
|
|
32
|
+
pygments.token.Name.Attribute: "entity.other.attribute-name",
|
|
33
|
+
pygments.token.Name.Variable: "variable",
|
|
34
|
+
pygments.token.Name.Variable.Magic: "variable",
|
|
35
|
+
pygments.token.Name.Builtin: "constant.language",
|
|
36
|
+
pygments.token.Name.Builtin.Pseudo: "constant.language",
|
|
37
|
+
pygments.token.Name.Namespace: "constant.language",
|
|
38
|
+
|
|
39
|
+
pygments.token.Literal.String: "string",
|
|
40
|
+
pygments.token.Literal.String.Doc: "string",
|
|
41
|
+
pygments.token.Literal.String.Double: "string",
|
|
42
|
+
pygments.token.Literal.String.Regex: "string",
|
|
43
|
+
pygments.token.Literal.String.Backtick: "string",
|
|
44
|
+
pygments.token.Literal.String.Interpol: "string.interpolated",
|
|
45
|
+
pygments.token.Literal.Number: "constant.numeric",
|
|
46
|
+
pygments.token.Literal.Number.Hex: "constant.numeric",
|
|
47
|
+
pygments.token.Literal.Number.Float: "constant.numeric",
|
|
48
|
+
pygments.token.Literal.Number.Integer: "constant.numeric",
|
|
49
|
+
|
|
50
|
+
pygments.token.Keyword: "keyword",
|
|
51
|
+
pygments.token.Keyword.Reserved: "constant.language",
|
|
52
|
+
pygments.token.Keyword.Constant: "constant.language",
|
|
53
|
+
pygments.token.Keyword.Namespace: "keyword",
|
|
54
|
+
pygments.token.Keyword.Declaration: "keyword",
|
|
55
|
+
|
|
56
|
+
pygments.token.Error: "invalid",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
def lex(self, code, lex):
|
|
60
|
+
"""Return tokenified code.
|
|
61
|
+
|
|
62
|
+
Return a list of tuples (scope, word) where word is the word to be
|
|
63
|
+
printed and scope the scope name representing the context.
|
|
64
|
+
|
|
65
|
+
:param str code: Code to tokenify.
|
|
66
|
+
:param lex: Lexer to use.
|
|
67
|
+
:return:
|
|
68
|
+
"""
|
|
69
|
+
if lex is None:
|
|
70
|
+
if not type(code) is str:
|
|
71
|
+
# if not suitable lexer is found, return decoded code
|
|
72
|
+
code = code.decode("utf-8")
|
|
73
|
+
return (("global", code),)
|
|
74
|
+
|
|
75
|
+
words = pygments.lex(code, lex)
|
|
76
|
+
|
|
77
|
+
scopes = []
|
|
78
|
+
for word in words:
|
|
79
|
+
token = word[0]
|
|
80
|
+
scope = "global"
|
|
81
|
+
|
|
82
|
+
if token in self.token_map.keys():
|
|
83
|
+
scope = self.token_map[token]
|
|
84
|
+
else:
|
|
85
|
+
self.logger.warning("Token '{0}' for word '{1}' not found in token_map.".format(token, word[1]))
|
|
86
|
+
|
|
87
|
+
scopes.append((scope, word[1]))
|
|
88
|
+
return scopes
|
suplemon/line.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# -*- encoding: utf-8
|
|
2
|
+
"""
|
|
3
|
+
Line object to represent a single line in the text editor.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Line:
|
|
8
|
+
def __init__(self, data=""):
|
|
9
|
+
if isinstance(data, Line):
|
|
10
|
+
data = data.data
|
|
11
|
+
self.data = data
|
|
12
|
+
self.x_scroll = 0
|
|
13
|
+
self.number_color = 8
|
|
14
|
+
|
|
15
|
+
def __getitem__(self, i):
|
|
16
|
+
return self.data[i]
|
|
17
|
+
|
|
18
|
+
def __setitem__(self, i, v):
|
|
19
|
+
self.data[i] = v
|
|
20
|
+
|
|
21
|
+
def __str__(self):
|
|
22
|
+
return self.data
|
|
23
|
+
|
|
24
|
+
def __add__(self, other):
|
|
25
|
+
return Line(self.data + other)
|
|
26
|
+
|
|
27
|
+
def __radd__(self, other):
|
|
28
|
+
return Line(other + self.data)
|
|
29
|
+
|
|
30
|
+
def __len__(self):
|
|
31
|
+
return len(self.data)
|
|
32
|
+
|
|
33
|
+
def get_data(self):
|
|
34
|
+
return self.data
|
|
35
|
+
|
|
36
|
+
def set_data(self, data):
|
|
37
|
+
if isinstance(data, Line):
|
|
38
|
+
data = data.get_data()
|
|
39
|
+
self.data = data
|
|
40
|
+
|
|
41
|
+
def set_number_color(self, color):
|
|
42
|
+
self.number_color = color
|
|
43
|
+
|
|
44
|
+
def find(self, what, start=0):
|
|
45
|
+
return self.data.find(what, start)
|
|
46
|
+
|
|
47
|
+
def strip(self, *args):
|
|
48
|
+
return self.data.strip(*args)
|
|
49
|
+
|
|
50
|
+
def reset_number_color(self):
|
|
51
|
+
self.number_color = 8
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("/*", "*/")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
if line.startswith("@import"):
|
|
12
|
+
color = color_map["blue"]
|
|
13
|
+
elif line.startswith("$"):
|
|
14
|
+
color = color_map["green"]
|
|
15
|
+
elif line.startswith("/*") or line.endswith("*/"):
|
|
16
|
+
color = color_map["magenta"]
|
|
17
|
+
elif line.startswith("{") or line.endswith(("}", "{")):
|
|
18
|
+
color = color_map["cyan"]
|
|
19
|
+
elif line.endswith(";"):
|
|
20
|
+
color = color_map["yellow"]
|
|
21
|
+
return color
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("/*", "*/")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = str(raw_line)
|
|
11
|
+
if line.startswith("+"):
|
|
12
|
+
color = color_map["green"]
|
|
13
|
+
elif line.startswith("-"):
|
|
14
|
+
color = color_map["red"]
|
|
15
|
+
elif line.startswith("@@"):
|
|
16
|
+
color = color_map["blue"]
|
|
17
|
+
return color
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("<!--", "-->")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
if line.startswith(("#", "//", "/*", "*/", "<!--")):
|
|
12
|
+
color = color_map["magenta"]
|
|
13
|
+
elif line.endswith(("*/", "-->")):
|
|
14
|
+
color = color_map["magenta"]
|
|
15
|
+
elif line.startswith("<"):
|
|
16
|
+
color = color_map["cyan"]
|
|
17
|
+
elif line.endswith(">"):
|
|
18
|
+
color = color_map["cyan"]
|
|
19
|
+
return color
|
suplemon/linelight/js.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("//", "")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
if line.startswith("function"):
|
|
12
|
+
color = color_map["cyan"]
|
|
13
|
+
elif line.startswith("return"):
|
|
14
|
+
color = color_map["red"]
|
|
15
|
+
elif line.startswith("this."):
|
|
16
|
+
color = color_map["cyan"]
|
|
17
|
+
elif line.startswith(("//", "/*", "*/", "*")):
|
|
18
|
+
color = color_map["magenta"]
|
|
19
|
+
elif line.startswith(("if", "else", "for ", "while ", "continue", "break")):
|
|
20
|
+
color = color_map["yellow"]
|
|
21
|
+
return color
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self, line):
|
|
6
|
+
return ("", "")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
if line.startswith(("{", "}")):
|
|
12
|
+
color = color_map["yellow"]
|
|
13
|
+
elif line.startswith('"'):
|
|
14
|
+
color = color_map["green"]
|
|
15
|
+
return color
|
suplemon/linelight/md.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self, line):
|
|
6
|
+
return ("", "")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
if line.startswith(("*", "-")): # List
|
|
12
|
+
color = color_map["cyan"]
|
|
13
|
+
elif line.startswith("#"): # Header
|
|
14
|
+
color = color_map["green"]
|
|
15
|
+
elif line.startswith(">"): # Item description
|
|
16
|
+
color = color_map["yellow"]
|
|
17
|
+
elif raw_line.startswith(" "): # Code
|
|
18
|
+
color = color_map["magenta"]
|
|
19
|
+
return color
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("//", "")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
keywords = ("if", "else", "finally", "try", "catch", "foreach",
|
|
12
|
+
"while", "continue", "pass", "break")
|
|
13
|
+
if line.startswith(("include", "require")):
|
|
14
|
+
color = color_map["blue"]
|
|
15
|
+
elif line.startswith(("class", "public", "private", "function")):
|
|
16
|
+
color = color_map["green"]
|
|
17
|
+
elif line.startswith("def"):
|
|
18
|
+
color = color_map["cyan"]
|
|
19
|
+
elif line.startswith("return"):
|
|
20
|
+
color = color_map["red"]
|
|
21
|
+
elif line.startswith("$"):
|
|
22
|
+
color = color_map["cyan"]
|
|
23
|
+
elif line.startswith(("#", "//", "/*", "*/")):
|
|
24
|
+
color = color_map["magenta"]
|
|
25
|
+
elif line.startswith(keywords):
|
|
26
|
+
color = color_map["yellow"]
|
|
27
|
+
return color
|
suplemon/linelight/py.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from suplemon.linelight.color_map import color_map
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Syntax:
|
|
5
|
+
def get_comment(self):
|
|
6
|
+
return ("# ", "")
|
|
7
|
+
|
|
8
|
+
def get_color(self, raw_line):
|
|
9
|
+
color = color_map["white"]
|
|
10
|
+
line = raw_line.strip()
|
|
11
|
+
keywords = ("if", "elif", "else", "finally", "try", "except",
|
|
12
|
+
"for ", "while ", "continue", "pass", "break")
|
|
13
|
+
if line.startswith(("import", "from")):
|
|
14
|
+
color = color_map["blue"]
|
|
15
|
+
elif line.startswith("class"):
|
|
16
|
+
color = color_map["green"]
|
|
17
|
+
elif line.startswith("def"):
|
|
18
|
+
color = color_map["cyan"]
|
|
19
|
+
elif line.startswith(("return", "yield")):
|
|
20
|
+
color = color_map["red"]
|
|
21
|
+
elif line.startswith("self."):
|
|
22
|
+
color = color_map["cyan"]
|
|
23
|
+
elif line.startswith(("#", "//", '"', "'", ":")):
|
|
24
|
+
color = color_map["magenta"]
|
|
25
|
+
elif line.startswith(keywords):
|
|
26
|
+
color = color_map["yellow"]
|
|
27
|
+
return color
|
suplemon/logger.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic logging to delay printing until curses is unloaded.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import logging
|
|
6
|
+
from logging.handlers import BufferingHandler, RotatingFileHandler
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Define an mix of BufferingHandler and MemoryHandler which store records internally and flush on `close`
|
|
11
|
+
# https://docs.python.org/3.3/library/logging.handlers.html#logging.handlers.BufferingHandler
|
|
12
|
+
# https://docs.python.org/3.3/library/logging.handlers.html#logging.handlers.MemoryHandler
|
|
13
|
+
class BufferingTargetHandler(BufferingHandler):
|
|
14
|
+
# Set up capacity and target for MemoryHandler
|
|
15
|
+
def __init__(self, capacity, fd_target):
|
|
16
|
+
"""
|
|
17
|
+
:param int capacity: Amount of records to store in memory
|
|
18
|
+
https://github.com/python/cpython/blob/3.3/Lib/logging/handlers.py#L1161-L1176
|
|
19
|
+
:param object fd_target: File descriptor to write output to (e.g. `sys.stdout`)
|
|
20
|
+
"""
|
|
21
|
+
# Call our BufferingHandler init
|
|
22
|
+
if issubclass(BufferingTargetHandler, object):
|
|
23
|
+
super(BufferingTargetHandler, self).__init__(capacity)
|
|
24
|
+
else:
|
|
25
|
+
BufferingHandler.__init__(self, capacity)
|
|
26
|
+
|
|
27
|
+
# Save target for later
|
|
28
|
+
self._fd_target = fd_target
|
|
29
|
+
|
|
30
|
+
# Records printed to the target, so callers can tell whether the user
|
|
31
|
+
# was actually shown anything
|
|
32
|
+
self.flushed_records = 0
|
|
33
|
+
|
|
34
|
+
def close(self):
|
|
35
|
+
"""Upon `close`, flush our internal info to the target"""
|
|
36
|
+
# Flush our buffers to the target
|
|
37
|
+
# https://github.com/python/cpython/blob/3.3/Lib/logging/handlers.py#L1185
|
|
38
|
+
# https://github.com/python/cpython/blob/3.3/Lib/logging/handlers.py#L1241-L1256
|
|
39
|
+
self.acquire()
|
|
40
|
+
try:
|
|
41
|
+
for record in self.buffer:
|
|
42
|
+
if record.levelno < self.level:
|
|
43
|
+
continue
|
|
44
|
+
msg = self.format(record)
|
|
45
|
+
print(msg, file=self._fd_target)
|
|
46
|
+
self.flushed_records += 1
|
|
47
|
+
finally:
|
|
48
|
+
self.release()
|
|
49
|
+
|
|
50
|
+
# Then, run our normal close actions
|
|
51
|
+
if issubclass(BufferingTargetHandler, object):
|
|
52
|
+
super(BufferingTargetHandler, self).close()
|
|
53
|
+
else:
|
|
54
|
+
BufferingHandler.close(self)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# Initialize logging
|
|
58
|
+
logging.basicConfig(level=logging.NOTSET)
|
|
59
|
+
logger = logging.getLogger()
|
|
60
|
+
logger.handlers = []
|
|
61
|
+
|
|
62
|
+
# Generate and configure handlers
|
|
63
|
+
log_filepath = os.path.join(os.path.expanduser("~"), ".config", "suplemon", "output.log")
|
|
64
|
+
logger_handlers = [
|
|
65
|
+
# Buffer 64k records in memory at a time
|
|
66
|
+
BufferingTargetHandler(64 * 1024, fd_target=sys.stderr),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
# Error recovery when log_filepath isn't writable
|
|
70
|
+
try:
|
|
71
|
+
if not os.path.exists(os.path.dirname(log_filepath)):
|
|
72
|
+
os.makedirs(os.path.dirname(log_filepath))
|
|
73
|
+
# Output up to 4MB of records to `~/.config/suplemon/output.log` for live debugging
|
|
74
|
+
# https://docs.python.org/3.3/library/logging.handlers.html#logging.handlers.RotatingFileHandler
|
|
75
|
+
# DEV: We use append mode to prevent erasing out logs
|
|
76
|
+
# DEV: We use 1 backup count since it won't truncate otherwise =/
|
|
77
|
+
rfh = RotatingFileHandler(log_filepath, mode="a+", maxBytes=(4 * 1024 * 1024), backupCount=1)
|
|
78
|
+
logger_handlers.append(rfh)
|
|
79
|
+
except OSError:
|
|
80
|
+
# Can't recover and can't log this error
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
fmt = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
84
|
+
logger_formatter = logging.Formatter(fmt)
|
|
85
|
+
for logger_handler in logger_handlers:
|
|
86
|
+
logger_handler.setFormatter(logger_formatter)
|
|
87
|
+
|
|
88
|
+
# Save handlers for our logger
|
|
89
|
+
for logger_handler in logger_handlers:
|
|
90
|
+
logger.addHandler(logger_handler)
|