1
1
# flake8: noqa: W503
2
+ from concurrent .futures import ThreadPoolExecutor
2
3
from pathlib import Path
3
4
from shutil import rmtree
4
5
6
+ from tornado .concurrent import run_on_executor
7
+ from tornado .gen import convert_yielded
8
+
5
9
from .manager import lsp_message_listener
6
10
from .paths import file_uri_to_path
7
11
12
+ # TODO: make configurable
13
+ MAX_WORKERS = 4
14
+
8
15
9
16
def extract_or_none (obj , path ):
10
17
for crumb in path :
@@ -16,11 +23,19 @@ def extract_or_none(obj, path):
16
23
17
24
18
25
class EditableFile :
26
+ executor = ThreadPoolExecutor (max_workers = MAX_WORKERS )
27
+
19
28
def __init__ (self , path ):
20
29
# Python 3.5 relict:
21
30
self .path = Path (path ) if isinstance (path , str ) else path
22
- self .lines = self .read_lines ()
23
31
32
+ async def read (self ):
33
+ self .lines = await convert_yielded (self .read_lines ())
34
+
35
+ async def write (self ):
36
+ return await convert_yielded (self .write_lines ())
37
+
38
+ @run_on_executor
24
39
def read_lines (self ):
25
40
# empty string required by the assumptions of the gluing algorithm
26
41
lines = ["" ]
@@ -30,6 +45,11 @@ def read_lines(self):
30
45
pass
31
46
return lines
32
47
48
+ @run_on_executor
49
+ def write_lines (self ):
50
+ self .path .parent .mkdir (parents = True , exist_ok = True )
51
+ self .path .write_text ("\n " .join (self .lines ))
52
+
33
53
@staticmethod
34
54
def trim (lines : list , character : int , side : int ):
35
55
needs_glue = False
@@ -63,10 +83,6 @@ def apply_change(self, text: str, start, end):
63
83
+ after [1 if needs_glue_right else None :]
64
84
) or ["" ]
65
85
66
- def write (self ):
67
- self .path .parent .mkdir (parents = True , exist_ok = True )
68
- self .path .write_text ("\n " .join (self .lines ))
69
-
70
86
@property
71
87
def full_range (self ):
72
88
start = {"line" : 0 , "character" : 0 }
@@ -125,7 +141,9 @@ async def shadow_virtual_documents(scope, message, language_server, manager):
125
141
return
126
142
127
143
path = file_uri_to_path (uri )
128
- file = EditableFile (path )
144
+ editable_file = EditableFile (path )
145
+
146
+ await editable_file .read ()
129
147
130
148
text = extract_or_none (document , ["text" ])
131
149
@@ -148,10 +166,10 @@ async def shadow_virtual_documents(scope, message, language_server, manager):
148
166
)
149
167
150
168
for change in changes [:1 ]:
151
- change_range = change .get ("range" , file .full_range )
152
- file .apply_change (change ["text" ], ** change_range )
169
+ change_range = change .get ("range" , editable_file .full_range )
170
+ editable_file .apply_change (change ["text" ], ** change_range )
153
171
154
- file .write ()
172
+ await editable_file .write ()
155
173
156
174
return path
157
175
0 commit comments