Skip to content

Commit b88d612

Browse files
committed
Add settings for worker thread, and add worker version server proxies
1 parent 009dd15 commit b88d612

File tree

9 files changed

+141
-27
lines changed

9 files changed

+141
-27
lines changed

Preferences.sublime-settings

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"typescript_auto_format": true,
3-
"auto_complete_commit_on_tab": true
3+
"auto_complete_commit_on_tab": true,
4+
"project_error_list": false
45
}

TypeScript.sublime-commands

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
{ "caption" : "TypeScript: Rename", "command": "typescript_rename" },
1111
{ "caption" : "TypeScript: PasteAndFormat", "command": "typescript_paste_and_format" },
1212
{ "caption" : "TypeScript: FormatLine", "command": "typescript_format_line" },
13-
{ "caption" : "TypeScript: FormatBlock", "command": "typescript_format_brackets" }
13+
{ "caption" : "TypeScript: FormatBlock", "command": "typescript_format_brackets" },
14+
{ "caption" : "TypeScript: ShowErrorList", "command": "typescript_project_error_list" }
1415
]

typescript/commands/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .error_info import TypescriptErrorInfo
1+
from .error_info import TypescriptErrorInfo, TypescriptProjectErrorList
22
from .go_to_definition import TypescriptGoToDefinitionCommand
33
from .go_to_type import TypescriptGoToTypeCommand
44
from .nav_to import TypescriptNavToCommand
@@ -31,6 +31,7 @@
3131
__all__ = [
3232
"TypescriptAutoIndentOnEnterBetweenCurlyBrackets",
3333
"TypescriptErrorInfo",
34+
"TypescriptProjectErrorList",
3435
"TypescriptFormatBrackets",
3536
"TypescriptFormatDocument",
3637
"TypescriptFormatLine",

typescript/commands/error_info.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sublime_plugin
22

33
from ..libs.view_helpers import cli
4-
from .base_command import TypeScriptBaseTextCommand
4+
from .base_command import TypeScriptBaseTextCommand, TypeScriptBaseWindowCommand
55

66

77
class TypescriptErrorInfo(TypeScriptBaseTextCommand):
@@ -25,3 +25,14 @@ def run(self, text):
2525
self.view.set_status("typescript_error", error_text)
2626
else:
2727
self.view.erase_status("typescript_error")
28+
29+
30+
class TypescriptProjectErrorList(TypeScriptBaseWindowCommand):
31+
32+
error_list_panel = None
33+
34+
def run(self):
35+
# if self.window.get_output_panel("errorList") is None:
36+
if not TypescriptProjectErrorList.error_list_panel:
37+
TypescriptProjectErrorList.error_list_panel = self.window.create_output_panel("errorList")
38+
self.window.run_command("show_panel", {"panel": "output.errorList"})

typescript/libs/editor_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self):
3636
self.translate_tab_to_spaces = False
3737
self.ts_auto_format_enabled = True
3838
self.ts_auto_indent_enabled = True
39+
self.project_error_list_enabled = False
3940
self.auto_match_enabled = True
4041

4142
def initialize(self):
@@ -69,6 +70,9 @@ def initialize(self):
6970
settings.add_on_change(setting_name, self.load_format_settings)
7071
self.load_format_settings()
7172

73+
# project_error_list should only be set once.
74+
self.project_error_list_enabled = settings.get('project_error_list')
75+
7276
self.initialized = True
7377

7478
def load_format_settings(self):

typescript/libs/node_client.py

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,29 @@
1717

1818

1919
class CommClient:
20+
def serverStarted(self): pass
21+
22+
def workerStarted(self): pass
23+
2024
def getEvent(self): pass
2125

26+
def getEventFromWorker(self): pass
27+
2228
def postCmd(self, cmd): pass
2329

30+
def postCmdToWorker(self, cmd): pass
31+
2432
def sendCmd(self, cb, cmd): pass
2533

34+
def sendCmdToWorker(self, cmd): pass
35+
2636
def sendCmdSync(self, cmd): pass
2737

38+
def sendCmdToWorkerSync(self, cmd): pass
39+
2840
def sendCmdAsync(self, cmd): pass
2941

30-
def postCmdToWorker(self, cmd): pass
42+
def sendCmdToWorkerAsync(self, cmd): pass
3143

3244

3345
class NodeCommClient(CommClient):
@@ -45,6 +57,7 @@ def __init__(self, scriptPath):
4557
# create response and event queues
4658
self.__msgq = queue.Queue()
4759
self.__eventq = queue.Queue()
60+
self.__worker_eventq = queue.Queue()
4861

4962
# start node process
5063
pref_settings = sublime.load_settings('Preferences.sublime-settings')
@@ -92,18 +105,19 @@ def __init__(self, scriptPath):
92105
readerThread.daemon = True
93106
readerThread.start()
94107

95-
# start the worker thread
96-
if self.__workerProc and not self.__workerProc.poll():
97-
log.debug("worker proc {0}".format(self.__workerProc))
98-
log.debug("starting worker thread")
99-
worker_thread = threading.Thread(
100-
target = NodeCommClient.__reader,
101-
args = (
102-
self.__workerProc.stdout, self.__msgq, self.__eventq, self.asyncReq, self.__workerProc
108+
if pref_settings.get('project_error_list'):
109+
# start the worker thread
110+
if self.__workerProc and not self.__workerProc.poll():
111+
log.debug("worker proc {0}".format(self.__workerProc))
112+
log.debug("starting worker thread")
113+
worker_thread = threading.Thread(
114+
target=NodeCommClient.__reader,
115+
args=(
116+
self.__workerProc.stdout, self.__msgq, self.__worker_eventq, self.asyncReq, self.__workerProc
117+
)
103118
)
104-
)
105-
worker_thread.daemon = True
106-
worker_thread.start()
119+
worker_thread.daemon = True
120+
worker_thread.start()
107121

108122
self.__debugProc = None
109123
self.__breakpoints = []
@@ -165,6 +179,13 @@ def sendCmdAsync(self, cmd, seq, cb):
165179
if self.postCmd(cmd):
166180
self.asyncReq[seq] = cb
167181

182+
def sendCmdToWorkerAsync(self, cmd, seq, cb):
183+
"""
184+
Sends the command and registers a callback
185+
"""
186+
if self.postCmdToWorker(cmd):
187+
self.asyncReq[seq] = cb
188+
168189
def sendCmdSync(self, cmd, seq):
169190
"""
170191
Sends the command and wait for the result and returns it
@@ -183,6 +204,24 @@ def sendCmdSync(self, cmd, seq):
183204
else:
184205
return self.makeTimeoutMsg(cmd, seq)
185206

207+
def sendCmdToWorkerSync(self, cmd, seq):
208+
"""
209+
Sends the command and wait for the result and returns it
210+
"""
211+
if self.postCmdToWorker(cmd):
212+
reqSeq = -1
213+
try:
214+
while reqSeq < seq:
215+
data = self.__msgq.get(True, 1)
216+
dict = json_helpers.decode(data)
217+
reqSeq = dict['request_seq']
218+
return dict
219+
except queue.Empty:
220+
print("queue timeout")
221+
return self.makeTimeoutMsg(cmd, seq)
222+
else:
223+
return self.makeTimeoutMsg(cmd, seq)
224+
186225
def postCmd(self, cmd):
187226
"""
188227
Post command to server; no response needed
@@ -221,6 +260,13 @@ def getEvent(self):
221260
return None
222261
return ev
223262

263+
def getEventFromWorker(self):
264+
try:
265+
ev = self.__worker_eventq.get(False)
266+
except:
267+
return None
268+
return ev
269+
224270
@staticmethod
225271
def __readMsg(stream, msgq, eventq, asyncReq, proc):
226272
"""

typescript/libs/service_proxy.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from . import json_helpers
44
from .node_client import CommClient
55
from .text_helpers import Location
6+
from .editor_client import cli
67

78

89
class ServiceProxy:
@@ -26,6 +27,8 @@ def configure(self, host_info="Sublime Text", file=None, format_options=None):
2627
req_dict = self.create_req_dict("configure", args)
2728
json_str = json_helpers.encode(req_dict)
2829
response_dict = self.__comm.sendCmdSync(json_str, req_dict["seq"])
30+
if self.__comm.workerStarted():
31+
self.__comm.sendCmdToWorkerSync(json_str, req_dict["seq"])
2932
return response_dict
3033

3134
def change(self, path, begin_location=Location(1, 1), end_location=Location(1, 1), insertString=""):
@@ -40,7 +43,8 @@ def change(self, path, begin_location=Location(1, 1), end_location=Location(1, 1
4043
req_dict = self.create_req_dict("change", args)
4144
json_str = json_helpers.encode(req_dict)
4245
self.__comm.postCmd(json_str)
43-
self.__comm.postCmdToWorker(json_str)
46+
if self.__comm.workerStarted():
47+
self.__comm.postCmdToWorker(json_str)
4448

4549
def completions(self, path, location=Location(1, 1), prefix="", on_completed=None):
4650
args = {"file": path, "line": location.line, "offset": location.offset, "prefix": prefix}
@@ -92,28 +96,34 @@ def format(self, path, begin_location=Location(1, 1), end_location=Location(1, 1
9296
req_dict = self.create_req_dict("format", args)
9397
json_str = json_helpers.encode(req_dict)
9498
response_dict = self.__comm.sendCmdSync(json_str, req_dict["seq"])
99+
if self.__comm.workerStarted():
100+
self.__comm.sendCmdToWorkerSync(json_str, req_dict["seq"])
95101
return response_dict
96102

97103
def format_on_key(self, path, location=Location(1, 1), key=""):
98104
args = {"file": path, "line": location.line, "offset": location.offset, "key": key}
99105
req_dict = self.create_req_dict("formatonkey", args)
100106
json_str = json_helpers.encode(req_dict)
101107
response_dict = self.__comm.sendCmdSync(json_str, req_dict["seq"])
108+
if self.__comm.workerStarted():
109+
self.__comm.sendCmdToWorkerSync(json_str, req_dict["seq"])
102110
return response_dict
103111

104112
def open(self, path):
105113
args = {"file": path}
106114
req_dict = self.create_req_dict("open", args)
107115
json_str = json_helpers.encode(req_dict)
108116
self.__comm.postCmd(json_str)
109-
self.__comm.postCmdToWorker(json_str)
117+
if self.__comm.workerStarted():
118+
self.__comm.postCmdToWorker(json_str)
110119

111120
def close(self, path):
112121
args = {"file": path}
113122
req_dict = self.create_req_dict("close", args)
114123
json_str = json_helpers.encode(req_dict)
115124
self.__comm.postCmd(json_str)
116-
self.__comm.postCmdToWorker(json_str)
125+
if self.__comm.workerStarted():
126+
self.__comm.postCmdToWorker(json_str)
117127

118128
def references(self, path, location=Location(1, 1)):
119129
args = {"file": path, "line": location.line, "offset": location.offset}
@@ -126,28 +136,40 @@ def reload(self, path, alternate_path):
126136
args = {"file": path, "tmpfile": alternate_path}
127137
req_dict = self.create_req_dict("reload", args)
128138
json_str = json_helpers.encode(req_dict)
129-
self.__comm.postCmd(json_str)
130-
self.__comm.postCmdToWorker(json_str)
139+
response_dict = self.__comm.sendCmdSync(json_str, req_dict["seq"])
140+
if self.__comm.workerStarted():
141+
self.__comm.sendCmdToWorkerSync(json_str, req_dict["seq"])
142+
return response_dict
131143

132144
def reload_async(self, path, alternate_path, on_completed):
133145
args = {"file": path, "tmpfile": alternate_path}
134146
req_dict = self.create_req_dict("reload", args)
135147
json_str = json_helpers.encode(req_dict)
136148
self.__comm.sendCmdAsync(json_str, req_dict["seq"], on_completed)
137-
self.__comm.postCmdToWorker(json_str)
149+
if self.__comm.workerStarted():
150+
self.__comm.sendCmdToWorkerAsync(json_str, req_dict["seq"], None)
138151

139152
def rename(self, path, location=Location(1, 1)):
140153
args = {"file": path, "line": location.line, "offset": location.offset}
141154
req_dict = self.create_req_dict("rename", args)
142155
json_str = json_helpers.encode(req_dict)
143156
response_dict = self.__comm.sendCmdSync(json_str, req_dict["seq"])
157+
if self.__comm.workerStarted():
158+
self.__comm.sendCmdSync(json_str, req_dict["seq"])
144159
return response_dict
145160

146161
def request_get_err(self, delay=0, pathList=[]):
147162
args = {"files": pathList, "delay": delay}
148163
req_dict = self.create_req_dict("geterr", args)
149164
json_str = json_helpers.encode(req_dict)
150-
self.__comm.postCmdToWorker(json_str)
165+
self.__comm.postCmd(json_str)
166+
167+
def request_get_err_for_project(self, delay=0, path=""):
168+
args = {"file": path, "delay": delay}
169+
req_dict = self.create_req_dict("geterrForProject", args)
170+
json_str = json_helpers.encode(req_dict)
171+
if self.__comm.workerStarted():
172+
self.__comm.postCmdToWorker(json_str)
151173

152174
def type(self, path, location=Location(1, 1)):
153175
args = {"file": path, "line": location.line, "offset": location.offset}
@@ -170,6 +192,10 @@ def get_event(self):
170192
event_json_str = self.__comm.getEvent()
171193
return json_helpers.decode(event_json_str) if event_json_str is not None else None
172194

195+
def get_event_from_worker(self):
196+
event_json_str = self.__comm.getEventFromWorker()
197+
return json_helpers.decode(event_json_str) if event_json_str is not None else None
198+
173199
def save_to(self, path, alternatePath):
174200
args = {"file": path, "tmpfile": alternatePath}
175201
req_dict = self.create_req_dict("saveto", args)

typescript/libs/view_helpers.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ def get_info(view):
5757
reload_buffer(view, info.client_info)
5858
else:
5959
info.client_info.pending_changes = True
60-
# if info in most_recent_used_file_list:
61-
# most_recent_used_file_list.remove(info)
62-
# most_recent_used_file_list.append(info)
60+
# if info in most_recent_used_file_list:
61+
# most_recent_used_file_list.remove(info)
62+
# most_recent_used_file_list.append(info)
6363
return info
6464

6565

@@ -213,10 +213,12 @@ def reload_buffer(view, client_info=None):
213213
client_info.change_count = info.modify_count
214214
client_info.pending_changes = False
215215

216+
216217
def reload_required(view):
217218
client_info = cli.get_or_add_file(view.file_name())
218219
return client_info.pending_changes or client_info.change_count < change_count(view)
219220

221+
220222
def check_update_view(view):
221223
"""Check if the buffer in the view needs to be reloaded
222224
@@ -315,4 +317,9 @@ def change_count(view):
315317
if IS_ST2:
316318
return info.modify_count
317319
else:
318-
return view.change_count()
320+
return view.change_count()
321+
322+
323+
def is_view_visible(view):
324+
"""The only way to tell a view is visible seems to be to test if it has an attached window"""
325+
return view.window() is not None

typescript/listeners/idle.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from ..libs import log
44
from .event_hub import EventHub
55

6+
from ..commands import TypescriptProjectErrorList
7+
68

79
class IdleListener:
810
def __init__(self):
@@ -58,6 +60,8 @@ def request_errors(self, view, info, error_delay):
5860
check_update_view(group_active_view)
5961
if len(files) > 0:
6062
cli.service.request_get_err(error_delay, files)
63+
if cli.project_error_list_enabled:
64+
cli.service.request_get_err_for_project(error_delay, active_view().file_name())
6165
self.error_info_requested_not_received = True
6266
self.wait_count = 0
6367
self.set_on_idle_timer(error_delay + 300)
@@ -156,6 +160,15 @@ def handle_time_out(self):
156160
if self.pending_timeout == 0:
157161
self.on_idle()
158162

163+
def update_project_error_list(self):
164+
# Retrieve the project wide errors
165+
test_ev = cli.service.get_event_from_worker()
166+
error_list_panel = TypescriptProjectErrorList.error_list_panel
167+
if is_view_visible(error_list_panel):
168+
while test_ev:
169+
error_list_panel.run_command("append", {"characters": str(test_ev) + "\n"})
170+
test_ev = cli.service.get_event_from_worker()
171+
159172
def on_idle(self):
160173
"""Callback after the idle status is confirmed
161174
@@ -164,6 +177,10 @@ def on_idle(self):
164177
"""
165178
view = active_view()
166179
log.debug("call get_event from on_idle")
180+
181+
if cli.project_error_list_enabled:
182+
self.update_project_error_list()
183+
167184
ev = cli.service.get_event()
168185
if ev is not None:
169186
self.error_info_requested_not_received = False

0 commit comments

Comments
 (0)