|
1 |
| -import shutil |
2 | 1 | import os
|
| 2 | +import shutil |
3 | 3 | import sublime
|
4 |
| -import threading |
5 |
| -import subprocess |
6 | 4 |
|
7 | 5 | from LSP.plugin.core.handlers import LanguageHandler
|
8 |
| -from LSP.plugin.core.settings import ClientConfig, LanguageConfig, read_client_config |
| 6 | +from LSP.plugin.core.settings import ClientConfig, read_client_config |
| 7 | +from lsp_utils import ServerNpmResource |
9 | 8 |
|
| 9 | +PACKAGE_NAME = 'LSP-vue' |
| 10 | +SETTINGS_FILENAME = 'LSP-vue.sublime-settings' |
| 11 | +SERVER_DIRECTORY = 'server' |
| 12 | +SERVER_BINARY_PATH = os.path.join(SERVER_DIRECTORY, 'node_modules', 'vue-language-server', 'bin', 'vls') |
10 | 13 |
|
11 |
| -package_path = os.path.dirname(__file__) |
12 |
| -server_path = os.path.join(package_path, 'node_modules', 'vue-language-server', 'bin', 'vls') |
| 14 | +server = ServerNpmResource(PACKAGE_NAME, SERVER_DIRECTORY, SERVER_BINARY_PATH) |
13 | 15 |
|
14 | 16 |
|
15 | 17 | def plugin_loaded():
|
16 |
| - is_server_installed = os.path.isfile(server_path) |
17 |
| - print('LSP-vue: Server {} installed.'.format('is' if is_server_installed else 'is not' )) |
18 |
| - |
19 |
| - # install if not installed |
20 |
| - if not is_server_installed: |
21 |
| - # this will be called only when the plugin gets: |
22 |
| - # - installed for the first time, |
23 |
| - # - or when updated on package control |
24 |
| - logAndShowMessage('LSP-vue: Installing server.') |
25 |
| - |
26 |
| - runCommand( |
27 |
| - onCommandDone, |
28 |
| - ["npm", "install", "--verbose", "--prefix", package_path, package_path] |
29 |
| - ) |
30 |
| - |
31 |
| - |
32 |
| -def onCommandDone(): |
33 |
| - logAndShowMessage('LSP-vue: Server installed.') |
34 |
| - |
35 |
| - |
36 |
| -def runCommand(onExit, popenArgs): |
37 |
| - """ |
38 |
| - Runs the given args in a subprocess.Popen, and then calls the function |
39 |
| - onExit when the subprocess completes. |
40 |
| - onExit is a callable object, and popenArgs is a list/tuple of args that |
41 |
| - would give to subprocess.Popen. |
42 |
| - """ |
43 |
| - def runInThread(onExit, popenArgs): |
44 |
| - try: |
45 |
| - if sublime.platform() == 'windows': |
46 |
| - subprocess.check_call(popenArgs, shell=True) |
47 |
| - else: |
48 |
| - subprocess.check_call(popenArgs) |
49 |
| - onExit() |
50 |
| - except subprocess.CalledProcessError as error: |
51 |
| - logAndShowMessage('LSP-vue: Error while installing the server.', error) |
52 |
| - return |
53 |
| - thread = threading.Thread(target=runInThread, args=(onExit, popenArgs)) |
54 |
| - thread.start() |
55 |
| - # returns immediately after the thread starts |
56 |
| - return thread |
57 |
| - |
| 18 | + server.setup() |
58 | 19 |
|
59 |
| -def is_node_installed(): |
60 |
| - return shutil.which('node') is not None |
61 | 20 |
|
| 21 | +def plugin_unloaded(): |
| 22 | + server.cleanup() |
62 | 23 |
|
63 |
| -def logAndShowMessage(msg, additional_logs=None): |
64 |
| - print(msg, '\n', additional_logs) if additional_logs else print(msg) |
65 |
| - sublime.active_window().status_message(msg) |
66 | 24 |
|
| 25 | +def is_node_installed(): |
| 26 | + return shutil.which('node') is not None |
67 | 27 |
|
68 |
| -def update_to_new_configuration(settings, old_config, new_config): |
69 |
| - # add old config to new config |
70 |
| - new_config['initializationOptions']['config'] = old_config |
71 |
| - settings.set('client', new_config) |
72 |
| - # remove old config |
73 |
| - settings.erase('config') |
74 |
| - sublime.save_settings("LSP-vue.sublime-settings") |
75 | 28 |
|
76 | 29 | class LspVuePlugin(LanguageHandler):
|
77 | 30 | @property
|
78 | 31 | def name(self) -> str:
|
79 |
| - return 'lsp-vue' |
| 32 | + return PACKAGE_NAME.lower() |
80 | 33 |
|
81 | 34 | @property
|
82 | 35 | def config(self) -> ClientConfig:
|
83 |
| - settings = sublime.load_settings("LSP-vue.sublime-settings") |
84 |
| - # TODO: remove update_to_new_configuration after 1 November. |
85 |
| - old_config = settings.get('config') |
86 |
| - client_configuration = settings.get('client') |
87 |
| - if old_config: |
88 |
| - update_to_new_configuration(settings, old_config, client_configuration) |
| 36 | + # Calling setup() also here as this might run before `plugin_loaded`. |
| 37 | + # Will be a no-op if already ran. |
| 38 | + # See https://github.com/sublimelsp/LSP/issues/899 |
| 39 | + server.setup() |
| 40 | + |
| 41 | + configuration = self.migrate_and_read_configuration() |
89 | 42 |
|
90 | 43 | default_configuration = {
|
91 |
| - "command": [ |
92 |
| - 'node', |
93 |
| - server_path, |
94 |
| - '--stdio' |
95 |
| - ], |
96 |
| - "languages": [ |
97 |
| - { |
98 |
| - "languageId": "vue", |
99 |
| - "scopes": ["text.html.vue"], |
100 |
| - "syntaxes": ["Packages/Vue Syntax Highlight/Vue Component.sublime-syntax"] |
101 |
| - } |
102 |
| - ], |
103 |
| - "initializationOptions": { |
104 |
| - "config": { |
105 |
| - "vetur": { |
106 |
| - "completion": { |
107 |
| - "autoImport": False, |
108 |
| - "tagCasing": "kebab", |
109 |
| - "useScaffoldSnippets": False |
110 |
| - }, |
111 |
| - "format": { |
112 |
| - "defaultFormatter": { |
113 |
| - "js": "none", |
114 |
| - "ts": "none" |
115 |
| - }, |
116 |
| - "defaultFormatterOptions": {}, |
117 |
| - "scriptInitialIndent": False, |
118 |
| - "styleInitialIndent": False, |
119 |
| - "options": {} |
120 |
| - }, |
121 |
| - "useWorkspaceDependencies": False, |
122 |
| - "validation": { |
123 |
| - "script": True, |
124 |
| - "style": True, |
125 |
| - "template": True |
126 |
| - } |
127 |
| - }, |
128 |
| - "css": {}, |
129 |
| - "emmet": {}, |
130 |
| - "stylusSupremacy": {}, |
131 |
| - "html": { |
132 |
| - "suggest": {} |
133 |
| - }, |
134 |
| - "javascript": { |
135 |
| - "format": {} |
136 |
| - }, |
137 |
| - "typescript": { |
138 |
| - "format": {} |
139 |
| - } |
140 |
| - } |
141 |
| - } |
| 44 | + 'enabled': True, |
| 45 | + 'command': ['node', server.binary_path, '--stdio'], |
142 | 46 | }
|
143 |
| - default_configuration.update(client_configuration) |
| 47 | + |
| 48 | + default_configuration.update(configuration) |
| 49 | + |
144 | 50 | view = sublime.active_window().active_view()
|
145 |
| - if view is not None: |
146 |
| - options = default_configuration.get('initializationOptions', {}) .get('config',{}) .get('vetur',{}).get('format',{}).get('options',{ |
147 |
| - "tabSize": view.settings().get("tab_size", 4), |
148 |
| - "useTabs": not view.settings().get("translate_tabs_to_spaces", False) |
149 |
| - }) |
150 |
| - return read_client_config('lsp-vue', default_configuration) |
| 51 | + if view: |
| 52 | + view_settings = view.settings() |
| 53 | + default_configuration \ |
| 54 | + .setdefault('initializationOptions', {}) \ |
| 55 | + .setdefault('config', {}) \ |
| 56 | + .setdefault('vetur', {}) \ |
| 57 | + .setdefault('format', {}) \ |
| 58 | + .setdefault('options', {}) \ |
| 59 | + .update({ |
| 60 | + 'tabSize': view_settings.get('tab_size', 4), |
| 61 | + 'useTabs': not view_settings.get('translate_tabs_to_spaces', False) |
| 62 | + }) |
| 63 | + |
| 64 | + return read_client_config(self.name, default_configuration) |
| 65 | + |
| 66 | + def migrate_and_read_configuration(self) -> dict: |
| 67 | + settings = {} |
| 68 | + loaded_settings = sublime.load_settings(SETTINGS_FILENAME) |
| 69 | + |
| 70 | + if loaded_settings: |
| 71 | + if loaded_settings.has('client'): |
| 72 | + client = loaded_settings.get('client') |
| 73 | + loaded_settings.erase('client') |
| 74 | + # Migrate old keys |
| 75 | + for key in client: |
| 76 | + loaded_settings.set(key, client[key]) |
| 77 | + sublime.save_settings(SETTINGS_FILENAME) |
| 78 | + |
| 79 | + # Read configuration keys |
| 80 | + for key in ['languages', 'initializationOptions', 'settings']: |
| 81 | + settings[key] = loaded_settings.get(key) |
| 82 | + |
| 83 | + return settings |
151 | 84 |
|
152 | 85 | def on_start(self, window) -> bool:
|
153 | 86 | if not is_node_installed():
|
|
0 commit comments