diff --git a/Main.sublime-menu b/Main.sublime-menu index c59db3bd7..8aea68e8f 100644 --- a/Main.sublime-menu +++ b/Main.sublime-menu @@ -25,50 +25,50 @@ }, { "command": "lsp_source_action", - "args": {"id": -1} + "args": {"index": -1} }, { "caption": "LSP: Source Action", "children": [ { "command": "lsp_source_action", - "args": {"id": 0} + "args": {"index": 0} }, { "command": "lsp_source_action", - "args": {"id": 1} + "args": {"index": 1} }, { "command": "lsp_source_action", - "args": {"id": 2} + "args": {"index": 2} }, { "command": "lsp_source_action", - "args": {"id": 3} + "args": {"index": 3} }, { "command": "lsp_source_action", - "args": {"id": 4} + "args": {"index": 4} }, { "command": "lsp_source_action", - "args": {"id": 5} + "args": {"index": 5} }, { "command": "lsp_source_action", - "args": {"id": 6} + "args": {"index": 6} }, { "command": "lsp_source_action", - "args": {"id": 7} + "args": {"index": 7} }, { "command": "lsp_source_action", - "args": {"id": 8} + "args": {"index": 8} }, { "command": "lsp_source_action", - "args": {"id": 9} + "args": {"index": 9} } ] }, @@ -81,43 +81,43 @@ }, { "command": "lsp_refactor", - "args": {"id": 0} + "args": {"index": 0} }, { "command": "lsp_refactor", - "args": {"id": 1} + "args": {"index": 1} }, { "command": "lsp_refactor", - "args": {"id": 2} + "args": {"index": 2} }, { "command": "lsp_refactor", - "args": {"id": 3} + "args": {"index": 3} }, { "command": "lsp_refactor", - "args": {"id": 4} + "args": {"index": 4} }, { "command": "lsp_refactor", - "args": {"id": 5} + "args": {"index": 5} }, { "command": "lsp_refactor", - "args": {"id": 6} + "args": {"index": 6} }, { "command": "lsp_refactor", - "args": {"id": 7} + "args": {"index": 7} }, { "command": "lsp_refactor", - "args": {"id": 8} + "args": {"index": 8} }, { "command": "lsp_refactor", - "args": {"id": 9} + "args": {"index": 9} } ] }, diff --git a/README.md b/README.md index e670297fe..b5d8df1df 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,12 @@ -:information_source: You are reading the README of the `main` branch. This branch targets ST4. If you are looking for the ST3 version, switch to the [st3 branch](https://github.com/sublimelsp/LSP/tree/st3). -

LSP

- - - - - - - - - - - - -
+ + + +

Like an IDE, except it's the good parts. Learn more.

@@ -45,7 +34,6 @@ See more information in the [documentation](https://lsp.sublimetext.io) :open_bo ## Getting help If you have any problems, see the [troubleshooting](https://sublimelsp.github.io/LSP/troubleshooting/) guide for tips and known limitations. If the documentation cannot solve your problem, you can look for help in: - * The [#lsp](https://discordapp.com/channels/280102180189634562/645268178397560865) channel (join the [SublimeHQ Discord](https://discord.gg/TZ5WN8t) first!) * By [searching or creating a new issue](https://github.com/sublimelsp/LSP/issues) diff --git a/boot.py b/boot.py index a54c62206..dc4b8632e 100644 --- a/boot.py +++ b/boot.py @@ -21,8 +21,6 @@ from .plugin.core.open import opening_files from .plugin.core.panels import PanelName from .plugin.core.protocol import Error -from .plugin.core.registry import LspCollapseTreeItemCommand -from .plugin.core.registry import LspExpandTreeItemCommand from .plugin.core.registry import LspNextDiagnosticCommand from .plugin.core.registry import LspOpenLocationCommand from .plugin.core.registry import LspPrevDiagnosticCommand @@ -36,6 +34,8 @@ from .plugin.core.signature_help import LspSignatureHelpNavigateCommand from .plugin.core.signature_help import LspSignatureHelpShowCommand from .plugin.core.transports import kill_all_subprocesses +from .plugin.core.tree_view import LspCollapseTreeItemCommand +from .plugin.core.tree_view import LspExpandTreeItemCommand from .plugin.core.typing import Any, Optional, List, Type, Dict from .plugin.core.views import LspRunTextCommandHelperCommand from .plugin.document_link import LspOpenLinkCommand diff --git a/docs/src/language_servers.md b/docs/src/language_servers.md index 5fd037697..14f3dd399 100644 --- a/docs/src/language_servers.md +++ b/docs/src/language_servers.md @@ -480,7 +480,7 @@ There are multiple options: "command": ["solargraph", "stdio"], "selector": "source.ruby | text.html.ruby", "initializationOptions": { - "diagnostics": false + "diagnostics": true } } } diff --git a/language-ids.sublime-settings b/language-ids.sublime-settings index 85f29fa71..4f59059ec 100644 --- a/language-ids.sublime-settings +++ b/language-ids.sublime-settings @@ -3,15 +3,15 @@ // ------------------------------------- // // These are the "exceptional" base scopes. If a base scope is not in this -// map, then the rule is that we split the base scopes on the ".", and take -// the last element. The resuling string is assumed to be the language ID. +// map, nor the first two components or more match any of the entries here, then +// the rule is that we split the base scope on the ".", and take +// the second component. The resulting string is assumed to be the language ID. // -// Examples of this rule: +// Examples: // -// source.julia -> julia +// source.c++ -> cpp // source.rust -> rust // text.tex.latex -> latex -// text.html.vue -> vue // // The official list is maintained at // https://microsoft.github.io/language-server-protocol/specification#textDocumentItem @@ -21,103 +21,35 @@ // request at github.com/sublimelsp/LSP if you believe an entry is missing. { "source.c++": "cpp", - "source.coffee.gulpfile": "coffeescript", // https://github.com/SublimeText/AFileIcon + "source.coffee": "coffeescript", "source.cs": "csharp", - "source.css.tailwind": "css", // https://github.com/SublimeText/TailwindCSS "source.dosbatch": "bat", "source.fixedform-fortran": "fortran", // https://packagecontrol.io/packages/Fortran - "source.groovy.gradle": "groovy", // https://github.com/SublimeText/AFileIcon - "source.groovy.jenkins": "groovy", // https://github.com/SublimeText/AFileIcon "source.js": "javascript", - "source.js.eslint": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.gruntfile": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.gulpfile": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.postcss": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.puglint": "javascript", // https://github.com/SublimeText/AFileIcon "source.js.react": "javascriptreact", // https://github.com/Thom1729/Sublime-JS-Custom - "source.js.stylelint": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.unittest": "javascript", // https://github.com/SublimeText/AFileIcon - "source.js.webpack": "javascript", // https://github.com/SublimeText/AFileIcon "source.json-tmlanguage": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.babel": "json", // https://github.com/SublimeText/AFileIcon - "source.json.bower": "json", // https://github.com/SublimeText/AFileIcon - "source.json.composer": "json", // https://github.com/SublimeText/AFileIcon - "source.json.eslint": "json", // https://github.com/SublimeText/AFileIcon - "source.json.npm": "json", // https://github.com/SublimeText/AFileIcon - "source.json.postcss": "json", // https://github.com/SublimeText/AFileIcon - "source.json.puglint": "json", // https://github.com/SublimeText/AFileIcon - "source.json.settings": "json", // https://github.com/SublimeText/AFileIcon - "source.json.stylelint": "json", // https://github.com/SublimeText/AFileIcon "source.json.sublime": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.build": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.color-scheme": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.commands": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.completions": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.keymap": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.macro": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.menu": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.mousemap": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.project": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.settings": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.sublime.theme": "jsonc", // https://github.com/SublimeText/PackageDev - "source.json.tern": "json", // https://github.com/SublimeText/AFileIcon "source.jsx": "javascriptreact", - "source.jsx.unittest": "javascriptreact", // https://github.com/SublimeText/AFileIcon "source.Kotlin": "kotlin", // https://github.com/vkostyukov/kotlin-sublime-package "source.modern-fortran": "fortran", // https://packagecontrol.io/packages/Fortran "source.objc": "objective-c", "source.objc++": "objective-cpp", "source.shader": "shaderlab", // https://github.com/waqiju/unity_shader_st3 - "source.shell.bash": "shellscript", - "source.shell.docker": "shellscript", // https://github.com/SublimeText/AFileIcon - "source.shell.eslint": "shellscript", // https://github.com/SublimeText/AFileIcon - "source.shell.npm": "shellscript", // https://github.com/SublimeText/AFileIcon - "source.shell.ruby": "shellscript", // https://github.com/SublimeText/AFileIcon - "source.shell.stylelint": "shellscript", // https://github.com/SublimeText/AFileIcon + "source.shell": "shellscript", "source.ts": "typescript", "source.ts.react": "typescriptreact", // https://github.com/Thom1729/Sublime-JS-Custom - "source.ts.unittest": "typescript", // https://github.com/SublimeText/AFileIcon "source.tsx": "typescriptreact", - "source.tsx.unittest": "typescriptreact", // https://github.com/SublimeText/AFileIcon "source.unity.unity_shader": "shaderlab", // https://github.com/petereichinger/Unity3D-Shader - "source.viml.vimrc": "viml", // https://github.com/SublimeText/AFileIcon "source.yaml-tmlanguage": "yaml", // https://github.com/SublimeText/PackageDev - "source.yaml.circleci": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.docker": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.eslint": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.lock": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.procfile": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.stylelint": "yaml", // https://github.com/SublimeText/AFileIcon - "source.yaml.sublime.syntax": "yaml", // https://github.com/SublimeText/PackageDev - "source.yaml.yarn": "yaml", // https://github.com/SublimeText/AFileIcon "text.advanced_csv": "csv", // https://github.com/SublimeText/AFileIcon "text.django": "html", // https://github.com/willstott101/django-sublime-syntax - "text.html.basic": "html", - "text.html.elixir": "html", // https://github.com/elixir-editors/elixir-tmbundle - "text.html.markdown.academicmarkdown": "markdown", // https://github.com/mangecoeur/AcademicMarkdown - "text.html.markdown.license": "markdown", // https://github.com/SublimeText/AFileIcon + "text.html.handlebars": "handlebars", + "text.html.markdown": "markdown", "text.html.markdown.rmarkdown": "r", // https://github.com/REditorSupport/sublime-ide-r - "text.html.ngx": "html", // https://github.com/princemaple/ngx-html-syntax + "text.html.vue": "vue", "text.jinja": "html", // https://github.com/Sublime-Instincts/BetterJinja "text.plain": "plaintext", - "text.plain.buildpacks": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.eslint": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.fastq": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.license": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.lnk": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.log": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.nodejs": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.pcb": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.ps": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.python": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.readme": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.ruby": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.sketch": "plaintext", // https://github.com/SublimeText/AFileIcon - "text.plain.visualstudio": "plaintext", // https://github.com/SublimeText/AFileIcon "text.plist": "xml", // https://bitbucket.org/fschwehn/sublime_plist - "text.xml.plist": "xml", // https://github.com/SublimeText/PackageDev - "text.xml.plist.textmate.preferences": "xml", // https://github.com/SublimeText/PackageDev - "text.xml.sublime.snippet": "xml", // https://github.com/SublimeText/PackageDev - "text.xml.svg": "xml", // https://github.com/SublimeText/AFileIcon - "text.xml.visualstudio": "xml", // https://github.com/SublimeText/AFileIcon + "text.tex.latex": "latex", + "text.xml.xsl": "xsl", } diff --git a/plugin/code_actions.py b/plugin/code_actions.py index c55877346..2bd13d7db 100644 --- a/plugin/code_actions.py +++ b/plugin/code_actions.py @@ -365,17 +365,17 @@ def actions_cache(self) -> List[Tuple[str, CodeAction]]: def view(self) -> Optional[sublime.View]: return self.window.active_view() - def is_enabled(self, id: int, event: Optional[dict] = None) -> bool: - if not -1 < id < len(self.actions_cache): + def is_enabled(self, index: int, event: Optional[dict] = None) -> bool: + if not -1 < index < len(self.actions_cache): return False return self._has_session(event) - def is_visible(self, id: int, event: Optional[dict] = None) -> bool: - if id == -1: + def is_visible(self, index: int, event: Optional[dict] = None) -> bool: + if index == -1: if self._has_session(event): sublime.set_timeout_async(partial(self._request_menu_actions_async, event)) return False - return id < len(self.actions_cache) and self._is_cache_valid(event) + return index < len(self.actions_cache) and self._is_cache_valid(event) def _has_session(self, event: Optional[dict] = None) -> bool: view = self.view @@ -389,19 +389,19 @@ def _has_session(self, event: Optional[dict] = None) -> bool: return False return bool(listener.session_async(self.capability, region.b)) - def description(self, id: int, event: Optional[dict] = None) -> Optional[str]: - if -1 < id < len(self.actions_cache): - return self.actions_cache[id][1]['title'] + def description(self, index: int, event: Optional[dict] = None) -> Optional[str]: + if -1 < index < len(self.actions_cache): + return self.actions_cache[index][1]['title'] def want_event(self) -> bool: return True - def run(self, id: int, event: Optional[dict] = None) -> None: - sublime.set_timeout_async(partial(self.run_async, id, event)) + def run(self, index: int, event: Optional[dict] = None) -> None: + sublime.set_timeout_async(partial(self.run_async, index, event)) - def run_async(self, id: int, event: Optional[dict]) -> None: + def run_async(self, index: int, event: Optional[dict]) -> None: if self._is_cache_valid(event): - config_name, action = self.actions_cache[id] + config_name, action = self.actions_cache[index] session = self.session_by_name(config_name) if session: session.run_code_action_async(action, progress=True, view=self.view) \ diff --git a/plugin/code_lens.py b/plugin/code_lens.py index 7546065d1..778d3b7f5 100644 --- a/plugin/code_lens.py +++ b/plugin/code_lens.py @@ -94,7 +94,7 @@ def resolve_annotation(self, view_id: int) -> None: def resolve(self, view: sublime.View, code_lens_or_error: Union[CodeLens, Error]) -> None: if isinstance(code_lens_or_error, Error): self.is_resolve_error = True - self.annotation = html_escape(str(code_lens_or_error)) + self.annotation = 'error' return self.data = code_lens_or_error self.region = range_to_region(code_lens_or_error['range'], view) diff --git a/plugin/completion.py b/plugin/completion.py index 6efc612cf..2169eb097 100644 --- a/plugin/completion.py +++ b/plugin/completion.py @@ -1,3 +1,4 @@ +from .core.constants import COMPLETION_KINDS from .core.edit import parse_text_edit from .core.logging import debug from .core.promise import Promise @@ -19,7 +20,6 @@ from .core.sessions import Session from .core.settings import userprefs from .core.typing import Callable, List, Dict, Optional, Generator, Tuple, Union, cast, Any, TypeGuard -from .core.views import COMPLETION_KINDS from .core.views import FORMAT_STRING, FORMAT_MARKUP_CONTENT from .core.views import MarkdownLangMap from .core.views import minihtml diff --git a/plugin/core/configurations.py b/plugin/core/configurations.py index 96aecfe2e..1232de31b 100644 --- a/plugin/core/configurations.py +++ b/plugin/core/configurations.py @@ -3,6 +3,7 @@ from .logging import printf from .types import ClientConfig from .typing import Generator, List, Optional, Set, Dict, Deque +from .url import parse_uri from .workspace import enable_in_project, disable_in_project from abc import ABCMeta from abc import abstractmethod @@ -10,7 +11,6 @@ from datetime import datetime, timedelta from weakref import WeakSet import sublime -import urllib.parse RETRY_MAX_COUNT = 5 @@ -51,7 +51,7 @@ def match_view(self, view: sublime.View, include_disabled: bool = False) -> Gene uri = view.settings().get("lsp_uri") if not isinstance(uri, str): return - scheme = urllib.parse.urlparse(uri).scheme + scheme = parse_uri(uri)[0] for config in self.all.values(): if config.match_view(view, scheme) and (config.enabled or include_disabled): yield config @@ -62,7 +62,8 @@ def update(self, updated_config_name: Optional[str] = None) -> None: self._reload_configs(updated_config_name, notify_listeners=True) def _reload_configs(self, updated_config_name: Optional[str] = None, notify_listeners: bool = False) -> None: - project_settings = (self._window.project_data() or {}).get("settings", {}).get("LSP", {}) + project_data = self._window.project_data() + project_settings = project_data.get("settings", {}).get("LSP", {}) if isinstance(project_data, dict) else {} if updated_config_name is None: self.all.clear() for name, config in self._global_configs.items(): diff --git a/plugin/core/constants.py b/plugin/core/constants.py index 28207be8e..9fad27f35 100644 --- a/plugin/core/constants.py +++ b/plugin/core/constants.py @@ -1,6 +1,15 @@ +from .protocol import CodeActionKind +from .protocol import CompletionItemKind +from .protocol import DiagnosticSeverity +from .protocol import DocumentHighlightKind +from .protocol import SymbolKind +from .typing import Dict, Tuple import sublime +SublimeKind = Tuple[int, str, str] + + ST_VERSION = int(sublime.version()) # Keys for View.add_regions @@ -11,3 +20,196 @@ HOVER_ENABLED_KEY = 'lsp_show_hover_popups' HOVER_PROVIDER_COUNT_KEY = 'lsp_hover_provider_count' SHOW_DEFINITIONS_KEY = 'show_definitions' + +# sublime.Kind tuples for sublime.CompletionItem, sublime.QuickPanelItem, sublime.ListInputItem +# https://www.sublimetext.com/docs/api_reference.html#sublime.Kind +KIND_ARRAY = (sublime.KIND_ID_TYPE, "a", "Array") +KIND_BOOLEAN = (sublime.KIND_ID_VARIABLE, "b", "Boolean") +KIND_CLASS = (sublime.KIND_ID_TYPE, "c", "Class") +KIND_COLOR = (sublime.KIND_ID_MARKUP, "c", "Color") +KIND_CONSTANT = (sublime.KIND_ID_VARIABLE, "c", "Constant") +KIND_CONSTRUCTOR = (sublime.KIND_ID_FUNCTION, "c", "Constructor") +KIND_ENUM = (sublime.KIND_ID_TYPE, "e", "Enum") +KIND_ENUMMEMBER = (sublime.KIND_ID_VARIABLE, "e", "Enum Member") +KIND_EVENT = (sublime.KIND_ID_FUNCTION, "e", "Event") +KIND_FIELD = (sublime.KIND_ID_VARIABLE, "f", "Field") +KIND_FILE = (sublime.KIND_ID_NAVIGATION, "f", "File") +KIND_FOLDER = (sublime.KIND_ID_NAVIGATION, "f", "Folder") +KIND_FUNCTION = (sublime.KIND_ID_FUNCTION, "f", "Function") +KIND_INTERFACE = (sublime.KIND_ID_TYPE, "i", "Interface") +KIND_KEY = (sublime.KIND_ID_NAVIGATION, "k", "Key") +KIND_KEYWORD = (sublime.KIND_ID_KEYWORD, "k", "Keyword") +KIND_METHOD = (sublime.KIND_ID_FUNCTION, "m", "Method") +KIND_MODULE = (sublime.KIND_ID_NAMESPACE, "m", "Module") +KIND_NAMESPACE = (sublime.KIND_ID_NAMESPACE, "n", "Namespace") +KIND_NULL = (sublime.KIND_ID_VARIABLE, "n", "Null") +KIND_NUMBER = (sublime.KIND_ID_VARIABLE, "n", "Number") +KIND_OBJECT = (sublime.KIND_ID_TYPE, "o", "Object") +KIND_OPERATOR = (sublime.KIND_ID_KEYWORD, "o", "Operator") +KIND_PACKAGE = (sublime.KIND_ID_NAMESPACE, "p", "Package") +KIND_PROPERTY = (sublime.KIND_ID_VARIABLE, "p", "Property") +KIND_REFERENCE = (sublime.KIND_ID_NAVIGATION, "r", "Reference") +KIND_SNIPPET = (sublime.KIND_ID_SNIPPET, "s", "Snippet") +KIND_STRING = (sublime.KIND_ID_VARIABLE, "s", "String") +KIND_STRUCT = (sublime.KIND_ID_TYPE, "s", "Struct") +KIND_TEXT = (sublime.KIND_ID_MARKUP, "t", "Text") +KIND_TYPEPARAMETER = (sublime.KIND_ID_TYPE, "t", "Type Parameter") +KIND_UNIT = (sublime.KIND_ID_VARIABLE, "u", "Unit") +KIND_VALUE = (sublime.KIND_ID_VARIABLE, "v", "Value") +KIND_VARIABLE = (sublime.KIND_ID_VARIABLE, "v", "Variable") + +KIND_ERROR = (sublime.KIND_ID_COLOR_REDISH, "e", "Error") +KIND_WARNING = (sublime.KIND_ID_COLOR_YELLOWISH, "w", "Warning") +KIND_INFORMATION = (sublime.KIND_ID_COLOR_BLUISH, "i", "Information") +KIND_HINT = (sublime.KIND_ID_COLOR_BLUISH, "h", "Hint") + +KIND_QUICKFIX = (sublime.KIND_ID_COLOR_YELLOWISH, "f", "QuickFix") +KIND_REFACTOR = (sublime.KIND_ID_COLOR_CYANISH, "r", "Refactor") +KIND_SOURCE = (sublime.KIND_ID_COLOR_PURPLISH, "s", "Source") + +COMPLETION_KINDS = { + CompletionItemKind.Text: KIND_TEXT, + CompletionItemKind.Method: KIND_METHOD, + CompletionItemKind.Function: KIND_FUNCTION, + CompletionItemKind.Constructor: KIND_CONSTRUCTOR, + CompletionItemKind.Field: KIND_FIELD, + CompletionItemKind.Variable: KIND_VARIABLE, + CompletionItemKind.Class: KIND_CLASS, + CompletionItemKind.Interface: KIND_INTERFACE, + CompletionItemKind.Module: KIND_MODULE, + CompletionItemKind.Property: KIND_PROPERTY, + CompletionItemKind.Unit: KIND_UNIT, + CompletionItemKind.Value: KIND_VALUE, + CompletionItemKind.Enum: KIND_ENUM, + CompletionItemKind.Keyword: KIND_KEYWORD, + CompletionItemKind.Snippet: KIND_SNIPPET, + CompletionItemKind.Color: KIND_COLOR, + CompletionItemKind.File: KIND_FILE, + CompletionItemKind.Reference: KIND_REFERENCE, + CompletionItemKind.Folder: KIND_FOLDER, + CompletionItemKind.EnumMember: KIND_ENUMMEMBER, + CompletionItemKind.Constant: KIND_CONSTANT, + CompletionItemKind.Struct: KIND_STRUCT, + CompletionItemKind.Event: KIND_EVENT, + CompletionItemKind.Operator: KIND_OPERATOR, + CompletionItemKind.TypeParameter: KIND_TYPEPARAMETER +} # type: Dict[CompletionItemKind, SublimeKind] + +SYMBOL_KINDS = { + SymbolKind.File: KIND_FILE, + SymbolKind.Module: KIND_MODULE, + SymbolKind.Namespace: KIND_NAMESPACE, + SymbolKind.Package: KIND_PACKAGE, + SymbolKind.Class: KIND_CLASS, + SymbolKind.Method: KIND_METHOD, + SymbolKind.Property: KIND_PROPERTY, + SymbolKind.Field: KIND_FIELD, + SymbolKind.Constructor: KIND_CONSTRUCTOR, + SymbolKind.Enum: KIND_ENUM, + SymbolKind.Interface: KIND_INTERFACE, + SymbolKind.Function: KIND_FUNCTION, + SymbolKind.Variable: KIND_VARIABLE, + SymbolKind.Constant: KIND_CONSTANT, + SymbolKind.String: KIND_STRING, + SymbolKind.Number: KIND_NUMBER, + SymbolKind.Boolean: KIND_BOOLEAN, + SymbolKind.Array: KIND_ARRAY, + SymbolKind.Object: KIND_OBJECT, + SymbolKind.Key: KIND_KEY, + SymbolKind.Null: KIND_NULL, + SymbolKind.EnumMember: KIND_ENUMMEMBER, + SymbolKind.Struct: KIND_STRUCT, + SymbolKind.Event: KIND_EVENT, + SymbolKind.Operator: KIND_OPERATOR, + SymbolKind.TypeParameter: KIND_TYPEPARAMETER +} # type: Dict[SymbolKind, SublimeKind] + +DIAGNOSTIC_KINDS = { + DiagnosticSeverity.Error: KIND_ERROR, + DiagnosticSeverity.Warning: KIND_WARNING, + DiagnosticSeverity.Information: KIND_INFORMATION, + DiagnosticSeverity.Hint: KIND_HINT +} # type: Dict[DiagnosticSeverity, SublimeKind] + +CODE_ACTION_KINDS = { + CodeActionKind.QuickFix: KIND_QUICKFIX, + CodeActionKind.Refactor: KIND_REFACTOR, + CodeActionKind.Source: KIND_SOURCE +} # type: Dict[CodeActionKind, SublimeKind] + + +DOCUMENT_HIGHLIGHT_KIND_NAMES = { + DocumentHighlightKind.Text: "text", + DocumentHighlightKind.Read: "read", + DocumentHighlightKind.Write: "write" +} # type: Dict[DocumentHighlightKind, str] + + +# Symbol scope to kind mapping, based on https://github.com/sublimetext-io/docs.sublimetext.io/issues/30 +SUBLIME_KIND_SCOPES = { + sublime.KIND_KEYWORD: "keyword | storage.modifier | storage.type | keyword.declaration | variable.language | constant.language", # noqa: E501 + sublime.KIND_TYPE: "entity.name.type | entity.name.class | entity.name.enum | entity.name.trait | entity.name.struct | entity.name.impl | entity.name.interface | entity.name.union | support.type | support.class", # noqa: E501 + sublime.KIND_FUNCTION: "entity.name.function | entity.name.method | entity.name.macro | meta.method entity.name.function | support.function | meta.function-call variable.function | meta.function-call support.function | support.method | meta.method-call variable.function", # noqa: E501 + sublime.KIND_NAMESPACE: "entity.name.module | entity.name.namespace | support.module | support.namespace", + sublime.KIND_NAVIGATION: "entity.name.definition | entity.name.label | entity.name.section", + sublime.KIND_MARKUP: "entity.other.attribute-name | entity.name.tag | meta.toc-list.id.html", + sublime.KIND_VARIABLE: "entity.name.constant | constant.other | support.constant | variable.other | variable.parameter | variable.other.member | variable.other.readwrite.member" # noqa: E501 +} # type: Dict[SublimeKind, str] + +DOCUMENT_HIGHLIGHT_KIND_SCOPES = { + DocumentHighlightKind.Text: "region.bluish markup.highlight.text.lsp", + DocumentHighlightKind.Read: "region.greenish markup.highlight.read.lsp", + DocumentHighlightKind.Write: "region.yellowish markup.highlight.write.lsp" +} # type: Dict[DocumentHighlightKind, str] + +SEMANTIC_TOKENS_MAP = { + "namespace": "variable.other.namespace.lsp", + "namespace.declaration": "entity.name.namespace.lsp", + "namespace.definition": "entity.name.namespace.lsp", + "type": "storage.type.lsp", + "type.declaration": "entity.name.type.lsp", + "type.defaultLibrary": "support.type.lsp", + "type.definition": "entity.name.type.lsp", + "class": "storage.type.class.lsp", + "class.declaration": "entity.name.class.lsp", + "class.defaultLibrary": "support.class.lsp", + "class.definition": "entity.name.class.lsp", + "enum": "variable.other.enum.lsp", + "enum.declaration": "entity.name.enum.lsp", + "enum.definition": "entity.name.enum.lsp", + "interface": "entity.other.inherited-class.lsp", + "interface.declaration": "entity.name.interface.lsp", + "interface.definition": "entity.name.interface.lsp", + "struct": "storage.type.struct.lsp", + "struct.declaration": "entity.name.struct.lsp", + "struct.defaultLibrary": "support.struct.lsp", + "struct.definition": "entity.name.struct.lsp", + "typeParameter": "variable.parameter.generic.lsp", + "parameter": "variable.parameter.lsp", + "variable": "variable.other.lsp", + "variable.readonly": "variable.other.constant.lsp", + "property": "variable.other.property.lsp", + "enumMember": "constant.other.enum.lsp", + "event": "entity.name.function.lsp", + "function": "variable.function.lsp", + "function.declaration": "entity.name.function.lsp", + "function.defaultLibrary": "support.function.builtin.lsp", + "function.definition": "entity.name.function.lsp", + "method": "variable.function.lsp", + "method.declaration": "entity.name.function.lsp", + "method.defaultLibrary": "support.function.builtin.lsp", + "method.definition": "entity.name.function.lsp", + "macro": "variable.macro.lsp", + "macro.declaration": "entity.name.macro.lsp", + "macro.defaultLibrary": "support.macro.lsp", + "macro.definition": "entity.name.macro.lsp", + "keyword": "keyword.lsp", + "modifier": "storage.modifier.lsp", + "comment": "comment.lsp", + "comment.documentation": "comment.block.documentation.lsp", + "string": "string.lsp", + "number": "constant.numeric.lsp", + "regexp": "string.regexp.lsp", + "operator": "keyword.operator.lsp", + "decorator": "variable.annotation.lsp", +} diff --git a/plugin/core/registry.py b/plugin/core/registry.py index f07491bc5..c1708f3d9 100644 --- a/plugin/core/registry.py +++ b/plugin/core/registry.py @@ -3,8 +3,6 @@ from .protocol import LocationLink from .sessions import AbstractViewListener from .sessions import Session -from .tree_view import TreeDataProvider -from .tree_view import TreeViewSheet from .typing import Optional, Any, Generator, Iterable, List, Union from .views import first_selection_region from .views import get_uri_and_position_from_location @@ -16,56 +14,12 @@ from functools import partial import operator import sublime -import sublime_api # pyright: ignore[reportMissingImports] import sublime_plugin windows = WindowRegistry() -def new_tree_view_sheet( - window: sublime.Window, - name: str, - data_provider: TreeDataProvider, - header: str = "", - flags: int = 0, - group: int = -1 -) -> Optional[TreeViewSheet]: - """ - Use this function to create a new TreeView in form of a special HtmlSheet (TreeViewSheet). Only one TreeViewSheet - with the given name is allowed per window. If there already exists a TreeViewSheet with the same name, its content - will be replaced with the new data. The header argument is allowed to contain minihtml markup. - """ - wm = windows.lookup(window) - if not wm: - return None - if name in wm.tree_view_sheets: - tree_view_sheet = wm.tree_view_sheets[name] - sheet_id = tree_view_sheet.id() - if tree_view_sheet.window(): - tree_view_sheet.set_provider(data_provider, header) - if flags & sublime.ADD_TO_SELECTION: - # add to selected sheets if not already selected - selected_sheets = window.selected_sheets() - for sheet in window.sheets(): - if isinstance(sheet, sublime.HtmlSheet) and sheet.id() == sheet_id: - if sheet not in selected_sheets: - selected_sheets.append(sheet) - window.select_sheets(selected_sheets) - break - else: - window.focus_sheet(tree_view_sheet) - return tree_view_sheet - tree_view_sheet = TreeViewSheet( - sublime_api.window_new_html_sheet(window.window_id, name, "", flags, group), - name, - data_provider, - header - ) - wm.tree_view_sheets[name] = tree_view_sheet - return tree_view_sheet - - def best_session(view: sublime.View, sessions: Iterable[Session], point: Optional[int] = None) -> Optional[Session]: if point is None: try: @@ -320,28 +274,3 @@ class LspPrevDiagnosticCommand(LspTextCommand): def run(self, edit: sublime.Edit, point: Optional[int] = None) -> None: navigate_diagnostics(self.view, point, forward=False) - - -def toggle_tree_item(window: sublime.Window, name: str, id: str, expand: bool) -> None: - wm = windows.lookup(window) - if not wm: - return - sheet = wm.tree_view_sheets.get(name) - if not sheet: - return - if expand: - sheet.expand_item(id) - else: - sheet.collapse_item(id) - - -class LspExpandTreeItemCommand(LspWindowCommand): - - def run(self, name: str, id: str) -> None: - toggle_tree_item(self.window, name, id, True) - - -class LspCollapseTreeItemCommand(LspWindowCommand): - - def run(self, name: str, id: str) -> None: - toggle_tree_item(self.window, name, id, False) diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index c34ecee4a..7435cb12b 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -1,4 +1,5 @@ from .collections import DottedDict +from .constants import SEMANTIC_TOKENS_MAP from .diagnostics_storage import DiagnosticsStorage from .edit import apply_edits from .edit import parse_workspace_edit @@ -103,7 +104,6 @@ from .views import get_storage_path from .views import get_uri_and_range_from_location from .views import MarkdownLangMap -from .views import SEMANTIC_TOKENS_MAP from .workspace import is_subpath_of from .workspace import WorkspaceFolder from abc import ABCMeta diff --git a/plugin/core/tree_view.py b/plugin/core/tree_view.py index dfb253887..1a2030767 100644 --- a/plugin/core/tree_view.py +++ b/plugin/core/tree_view.py @@ -1,12 +1,15 @@ +from .constants import SublimeKind from .css import css from .promise import Promise +from .registry import LspWindowCommand +from .registry import windows from .typing import Dict, IntEnum, List, Optional, TypeVar -from .views import SublimeKind from abc import ABCMeta from abc import abstractmethod from functools import partial import html import sublime +import sublime_api # pyright: ignore[reportMissingImports] import uuid # pyright: reportInvalidTypeVarUse=false @@ -270,3 +273,71 @@ def _subtree_html(self, id: str) -> str: if node.tree_item.collapsible_state == TreeItemCollapsibleState.EXPANDED: html += "".join([self._subtree_html(child_id) for child_id in node.child_ids]) return html + + +def new_tree_view_sheet( + window: sublime.Window, + name: str, + data_provider: TreeDataProvider, + header: str = "", + flags: int = 0, + group: int = -1 +) -> Optional[TreeViewSheet]: + """ + Use this function to create a new TreeView in form of a special HtmlSheet (TreeViewSheet). Only one TreeViewSheet + with the given name is allowed per window. If there already exists a TreeViewSheet with the same name, its content + will be replaced with the new data. The header argument is allowed to contain minihtml markup. + """ + wm = windows.lookup(window) + if not wm: + return None + if name in wm.tree_view_sheets: + tree_view_sheet = wm.tree_view_sheets[name] + sheet_id = tree_view_sheet.id() + if tree_view_sheet.window(): + tree_view_sheet.set_provider(data_provider, header) + if flags & sublime.ADD_TO_SELECTION: + # add to selected sheets if not already selected + selected_sheets = window.selected_sheets() + for sheet in window.sheets(): + if isinstance(sheet, sublime.HtmlSheet) and sheet.id() == sheet_id: + if sheet not in selected_sheets: + selected_sheets.append(sheet) + window.select_sheets(selected_sheets) + break + else: + window.focus_sheet(tree_view_sheet) + return tree_view_sheet + tree_view_sheet = TreeViewSheet( + sublime_api.window_new_html_sheet(window.window_id, name, "", flags, group), + name, + data_provider, + header + ) + wm.tree_view_sheets[name] = tree_view_sheet + return tree_view_sheet + + +def toggle_tree_item(window: sublime.Window, name: str, id: str, expand: bool) -> None: + wm = windows.lookup(window) + if not wm: + return + sheet = wm.tree_view_sheets.get(name) + if not sheet: + return + if expand: + sheet.expand_item(id) + else: + sheet.collapse_item(id) + + +class LspExpandTreeItemCommand(LspWindowCommand): + + def run(self, name: str, id: str) -> None: + toggle_tree_item(self.window, name, id, True) + + +class LspCollapseTreeItemCommand(LspWindowCommand): + + def run(self, name: str, id: str) -> None: + toggle_tree_item(self.window, name, id, False) diff --git a/plugin/core/types.py b/plugin/core/types.py index c90805070..555e68b7f 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -16,7 +16,6 @@ import socket import sublime import time -import urllib.parse TCP_CONNECT_TIMEOUT = 5 # seconds @@ -36,7 +35,18 @@ def basescope2languageid(base_scope: str) -> str: # This the connection between Language IDs and ST selectors. base_scope_map = sublime.load_settings("language-ids.sublime-settings") - result = base_scope_map.get(base_scope, base_scope.split(".")[-1]) + result = "" + # Try to find exact match or less specific match consisting of at least 2 components. + scope_parts = base_scope.split('.') + while len(scope_parts) >= 2: + result = base_scope_map.get('.'.join(scope_parts)) + if result: + break + scope_parts.pop() + if not result: + # If no match, use the second component of the scope as the language ID. + scope_parts = base_scope.split('.') + result = scope_parts[1] if len(scope_parts) > 1 else scope_parts[0] return result if isinstance(result, str) else "" @@ -394,7 +404,7 @@ def __call__(self, view: sublime.View) -> bool: return False if self.scheme: uri = view.settings().get("lsp_uri") - if isinstance(uri, str) and urllib.parse.urlparse(uri).scheme != self.scheme: + if isinstance(uri, str) and parse_uri(uri)[0] != self.scheme: return False if self.pattern: if not globmatch(view.file_name() or "", self.pattern, flags=GLOBSTAR | BRACE): diff --git a/plugin/core/typing.py b/plugin/core/typing.py index b4cf3a3aa..be399071a 100644 --- a/plugin/core/typing.py +++ b/plugin/core/typing.py @@ -26,6 +26,7 @@ from typing import Set from typing import Tuple from typing import Type + from typing import TYPE_CHECKING from typing import TypedDict from typing import TypeGuard from typing import TypeVar @@ -33,6 +34,8 @@ else: + TYPE_CHECKING = False + def cast(typ, val): # type: ignore return val diff --git a/plugin/core/url.py b/plugin/core/url.py index 696ef9056..024379105 100644 --- a/plugin/core/url.py +++ b/plugin/core/url.py @@ -26,7 +26,7 @@ def filename_to_uri(file_name: str) -> str: def view_to_uri(view: sublime.View) -> str: file_name = view.file_name() if not file_name: - return "buffer://{}".format(view.buffer_id()) + return "buffer:{}".format(view.buffer_id()) return filename_to_uri(file_name) @@ -60,6 +60,9 @@ def parse_uri(uri: str) -> Tuple[str, str]: else: return parsed.scheme, path return parsed.scheme, path + elif parsed.scheme == '' and ':' in parsed.path.split('/')[0]: + # workaround for bug in urllib.parse.urlparse + return parsed.path.split(':')[0], uri return parsed.scheme, uri diff --git a/plugin/core/views.py b/plugin/core/views.py index 39e5ad07d..5ad99163e 100644 --- a/plugin/core/views.py +++ b/plugin/core/views.py @@ -1,3 +1,6 @@ +from .constants import CODE_ACTION_KINDS +from .constants import SUBLIME_KIND_SCOPES +from .constants import SublimeKind from .css import css as lsp_css from .protocol import CodeAction from .protocol import CodeActionKind @@ -7,7 +10,6 @@ from .protocol import Color from .protocol import ColorInformation from .protocol import Command -from .protocol import CompletionItemKind from .protocol import Diagnostic from .protocol import DiagnosticRelatedInformation from .protocol import DiagnosticSeverity @@ -16,7 +18,6 @@ from .protocol import DidOpenTextDocumentParams from .protocol import DidSaveTextDocumentParams from .protocol import DocumentColorParams -from .protocol import DocumentHighlightKind from .protocol import DocumentUri from .protocol import Location from .protocol import LocationLink @@ -28,7 +29,6 @@ from .protocol import Range from .protocol import Request from .protocol import SelectionRangeParams -from .protocol import SymbolKind from .protocol import TextDocumentContentChangeEvent from .protocol import TextDocumentIdentifier from .protocol import TextDocumentItem @@ -52,7 +52,6 @@ import tempfile MarkdownLangMap = Dict[str, Tuple[Tuple[str, ...], Tuple[str, ...]]] -SublimeKind = Tuple[int, str, str] DOCUMENT_LINK_FLAGS = sublime.HIDE_ON_MINIMAP | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE # noqa: E501 @@ -66,197 +65,6 @@ ("hint", "hints", "region.bluish markup.info.hint.lsp", "", _baseflags | sublime.DRAW_STIPPLED_UNDERLINE, sublime.DRAW_NO_FILL), # noqa: E501 ] # type: List[Tuple[str, str, str, str, int, int]] -# sublime.Kind tuples for sublime.CompletionItem, sublime.QuickPanelItem, sublime.ListInputItem -# https://www.sublimetext.com/docs/api_reference.html#sublime.Kind -KIND_ARRAY = (sublime.KIND_ID_TYPE, "a", "Array") -KIND_BOOLEAN = (sublime.KIND_ID_VARIABLE, "b", "Boolean") -KIND_CLASS = (sublime.KIND_ID_TYPE, "c", "Class") -KIND_COLOR = (sublime.KIND_ID_MARKUP, "c", "Color") -KIND_CONSTANT = (sublime.KIND_ID_VARIABLE, "c", "Constant") -KIND_CONSTRUCTOR = (sublime.KIND_ID_FUNCTION, "c", "Constructor") -KIND_ENUM = (sublime.KIND_ID_TYPE, "e", "Enum") -KIND_ENUMMEMBER = (sublime.KIND_ID_VARIABLE, "e", "Enum Member") -KIND_EVENT = (sublime.KIND_ID_FUNCTION, "e", "Event") -KIND_FIELD = (sublime.KIND_ID_VARIABLE, "f", "Field") -KIND_FILE = (sublime.KIND_ID_NAVIGATION, "f", "File") -KIND_FOLDER = (sublime.KIND_ID_NAVIGATION, "f", "Folder") -KIND_FUNCTION = (sublime.KIND_ID_FUNCTION, "f", "Function") -KIND_INTERFACE = (sublime.KIND_ID_TYPE, "i", "Interface") -KIND_KEY = (sublime.KIND_ID_NAVIGATION, "k", "Key") -KIND_KEYWORD = (sublime.KIND_ID_KEYWORD, "k", "Keyword") -KIND_METHOD = (sublime.KIND_ID_FUNCTION, "m", "Method") -KIND_MODULE = (sublime.KIND_ID_NAMESPACE, "m", "Module") -KIND_NAMESPACE = (sublime.KIND_ID_NAMESPACE, "n", "Namespace") -KIND_NULL = (sublime.KIND_ID_VARIABLE, "n", "Null") -KIND_NUMBER = (sublime.KIND_ID_VARIABLE, "n", "Number") -KIND_OBJECT = (sublime.KIND_ID_TYPE, "o", "Object") -KIND_OPERATOR = (sublime.KIND_ID_KEYWORD, "o", "Operator") -KIND_PACKAGE = (sublime.KIND_ID_NAMESPACE, "p", "Package") -KIND_PROPERTY = (sublime.KIND_ID_VARIABLE, "p", "Property") -KIND_REFERENCE = (sublime.KIND_ID_NAVIGATION, "r", "Reference") -KIND_SNIPPET = (sublime.KIND_ID_SNIPPET, "s", "Snippet") -KIND_STRING = (sublime.KIND_ID_VARIABLE, "s", "String") -KIND_STRUCT = (sublime.KIND_ID_TYPE, "s", "Struct") -KIND_TEXT = (sublime.KIND_ID_MARKUP, "t", "Text") -KIND_TYPEPARAMETER = (sublime.KIND_ID_TYPE, "t", "Type Parameter") -KIND_UNIT = (sublime.KIND_ID_VARIABLE, "u", "Unit") -KIND_VALUE = (sublime.KIND_ID_VARIABLE, "v", "Value") -KIND_VARIABLE = (sublime.KIND_ID_VARIABLE, "v", "Variable") - -KIND_ERROR = (sublime.KIND_ID_COLOR_REDISH, "e", "Error") -KIND_WARNING = (sublime.KIND_ID_COLOR_YELLOWISH, "w", "Warning") -KIND_INFORMATION = (sublime.KIND_ID_COLOR_BLUISH, "i", "Information") -KIND_HINT = (sublime.KIND_ID_COLOR_BLUISH, "h", "Hint") - -KIND_QUICKFIX = (sublime.KIND_ID_COLOR_YELLOWISH, "f", "QuickFix") -KIND_REFACTOR = (sublime.KIND_ID_COLOR_CYANISH, "r", "Refactor") -KIND_SOURCE = (sublime.KIND_ID_COLOR_PURPLISH, "s", "Source") - -COMPLETION_KINDS = { - CompletionItemKind.Text: KIND_TEXT, - CompletionItemKind.Method: KIND_METHOD, - CompletionItemKind.Function: KIND_FUNCTION, - CompletionItemKind.Constructor: KIND_CONSTRUCTOR, - CompletionItemKind.Field: KIND_FIELD, - CompletionItemKind.Variable: KIND_VARIABLE, - CompletionItemKind.Class: KIND_CLASS, - CompletionItemKind.Interface: KIND_INTERFACE, - CompletionItemKind.Module: KIND_MODULE, - CompletionItemKind.Property: KIND_PROPERTY, - CompletionItemKind.Unit: KIND_UNIT, - CompletionItemKind.Value: KIND_VALUE, - CompletionItemKind.Enum: KIND_ENUM, - CompletionItemKind.Keyword: KIND_KEYWORD, - CompletionItemKind.Snippet: KIND_SNIPPET, - CompletionItemKind.Color: KIND_COLOR, - CompletionItemKind.File: KIND_FILE, - CompletionItemKind.Reference: KIND_REFERENCE, - CompletionItemKind.Folder: KIND_FOLDER, - CompletionItemKind.EnumMember: KIND_ENUMMEMBER, - CompletionItemKind.Constant: KIND_CONSTANT, - CompletionItemKind.Struct: KIND_STRUCT, - CompletionItemKind.Event: KIND_EVENT, - CompletionItemKind.Operator: KIND_OPERATOR, - CompletionItemKind.TypeParameter: KIND_TYPEPARAMETER -} # type: Dict[CompletionItemKind, SublimeKind] - -SYMBOL_KINDS = { - SymbolKind.File: KIND_FILE, - SymbolKind.Module: KIND_MODULE, - SymbolKind.Namespace: KIND_NAMESPACE, - SymbolKind.Package: KIND_PACKAGE, - SymbolKind.Class: KIND_CLASS, - SymbolKind.Method: KIND_METHOD, - SymbolKind.Property: KIND_PROPERTY, - SymbolKind.Field: KIND_FIELD, - SymbolKind.Constructor: KIND_CONSTRUCTOR, - SymbolKind.Enum: KIND_ENUM, - SymbolKind.Interface: KIND_INTERFACE, - SymbolKind.Function: KIND_FUNCTION, - SymbolKind.Variable: KIND_VARIABLE, - SymbolKind.Constant: KIND_CONSTANT, - SymbolKind.String: KIND_STRING, - SymbolKind.Number: KIND_NUMBER, - SymbolKind.Boolean: KIND_BOOLEAN, - SymbolKind.Array: KIND_ARRAY, - SymbolKind.Object: KIND_OBJECT, - SymbolKind.Key: KIND_KEY, - SymbolKind.Null: KIND_NULL, - SymbolKind.EnumMember: KIND_ENUMMEMBER, - SymbolKind.Struct: KIND_STRUCT, - SymbolKind.Event: KIND_EVENT, - SymbolKind.Operator: KIND_OPERATOR, - SymbolKind.TypeParameter: KIND_TYPEPARAMETER -} # type: Dict[SymbolKind, SublimeKind] - -DIAGNOSTIC_KINDS = { - DiagnosticSeverity.Error: KIND_ERROR, - DiagnosticSeverity.Warning: KIND_WARNING, - DiagnosticSeverity.Information: KIND_INFORMATION, - DiagnosticSeverity.Hint: KIND_HINT -} # type: Dict[DiagnosticSeverity, SublimeKind] - -CODE_ACTION_KINDS = { - CodeActionKind.QuickFix: KIND_QUICKFIX, - CodeActionKind.Refactor: KIND_REFACTOR, - CodeActionKind.Source: KIND_SOURCE -} # type: Dict[CodeActionKind, SublimeKind] - -# Symbol scope to kind mapping, based on https://github.com/sublimetext-io/docs.sublimetext.io/issues/30 -SUBLIME_KIND_SCOPES = { - sublime.KIND_KEYWORD: "keyword | storage.modifier | storage.type | keyword.declaration | variable.language | constant.language", # noqa: E501 - sublime.KIND_TYPE: "entity.name.type | entity.name.class | entity.name.enum | entity.name.trait | entity.name.struct | entity.name.impl | entity.name.interface | entity.name.union | support.type | support.class", # noqa: E501 - sublime.KIND_FUNCTION: "entity.name.function | entity.name.method | entity.name.macro | meta.method entity.name.function | support.function | meta.function-call variable.function | meta.function-call support.function | support.method | meta.method-call variable.function", # noqa: E501 - sublime.KIND_NAMESPACE: "entity.name.module | entity.name.namespace | support.module | support.namespace", - sublime.KIND_NAVIGATION: "entity.name.definition | entity.name.label | entity.name.section", - sublime.KIND_MARKUP: "entity.other.attribute-name | entity.name.tag | meta.toc-list.id.html", - sublime.KIND_VARIABLE: "entity.name.constant | constant.other | support.constant | variable.other | variable.parameter | variable.other.member | variable.other.readwrite.member" # noqa: E501 -} # type: Dict[SublimeKind, str] - -DOCUMENT_HIGHLIGHT_KINDS = { - DocumentHighlightKind.Text: "text", - DocumentHighlightKind.Read: "read", - DocumentHighlightKind.Write: "write" -} # type: Dict[DocumentHighlightKind, str] - -DOCUMENT_HIGHLIGHT_KIND_SCOPES = { - DocumentHighlightKind.Text: "region.bluish markup.highlight.text.lsp", - DocumentHighlightKind.Read: "region.greenish markup.highlight.read.lsp", - DocumentHighlightKind.Write: "region.yellowish markup.highlight.write.lsp" -} # type: Dict[DocumentHighlightKind, str] - -SEMANTIC_TOKENS_MAP = { - "namespace": "variable.other.namespace.lsp", - "namespace.declaration": "entity.name.namespace.lsp", - "namespace.definition": "entity.name.namespace.lsp", - "type": "storage.type.lsp", - "type.declaration": "entity.name.type.lsp", - "type.defaultLibrary": "support.type.lsp", - "type.definition": "entity.name.type.lsp", - "class": "storage.type.class.lsp", - "class.declaration": "entity.name.class.lsp", - "class.defaultLibrary": "support.class.lsp", - "class.definition": "entity.name.class.lsp", - "enum": "variable.other.enum.lsp", - "enum.declaration": "entity.name.enum.lsp", - "enum.definition": "entity.name.enum.lsp", - "interface": "entity.other.inherited-class.lsp", - "interface.declaration": "entity.name.interface.lsp", - "interface.definition": "entity.name.interface.lsp", - "struct": "storage.type.struct.lsp", - "struct.declaration": "entity.name.struct.lsp", - "struct.defaultLibrary": "support.struct.lsp", - "struct.definition": "entity.name.struct.lsp", - "typeParameter": "variable.parameter.generic.lsp", - "parameter": "variable.parameter.lsp", - "variable": "variable.other.lsp", - "variable.readonly": "variable.other.constant.lsp", - "property": "variable.other.property.lsp", - "enumMember": "constant.other.enum.lsp", - "event": "entity.name.function.lsp", - "function": "variable.function.lsp", - "function.declaration": "entity.name.function.lsp", - "function.defaultLibrary": "support.function.builtin.lsp", - "function.definition": "entity.name.function.lsp", - "method": "variable.function.lsp", - "method.declaration": "entity.name.function.lsp", - "method.defaultLibrary": "support.function.builtin.lsp", - "method.definition": "entity.name.function.lsp", - "macro": "variable.macro.lsp", - "macro.declaration": "entity.name.macro.lsp", - "macro.defaultLibrary": "support.macro.lsp", - "macro.definition": "entity.name.macro.lsp", - "keyword": "keyword.lsp", - "modifier": "storage.modifier.lsp", - "comment": "comment.lsp", - "comment.documentation": "comment.block.documentation.lsp", - "string": "string.lsp", - "number": "constant.numeric.lsp", - "regexp": "string.regexp.lsp", - "operator": "keyword.operator.lsp", - "decorator": "variable.annotation.lsp", -} - class DiagnosticSeverityData: diff --git a/plugin/core/windows.py b/plugin/core/windows.py index 5ebebcc36..cd1e8b578 100644 --- a/plugin/core/windows.py +++ b/plugin/core/windows.py @@ -22,11 +22,10 @@ from .settings import client_configs from .settings import userprefs from .transports import create_transport -from .tree_view import TreeViewSheet from .types import ClientConfig from .types import matches_pattern from .types import sublime_pattern_to_glob -from .typing import Optional, Any, Dict, Deque, List, Generator, Tuple +from .typing import Optional, Any, Dict, Deque, List, Generator, Tuple, TYPE_CHECKING from .url import parse_uri from .views import extract_variables from .views import format_diagnostic_for_panel @@ -44,7 +43,10 @@ import json import sublime import threading -import urllib.parse + + +if TYPE_CHECKING: + from tree_view import TreeViewSheet _NO_DIAGNOSTICS_PLACEHOLDER = " No diagnostics. Well done!" @@ -184,7 +186,7 @@ def _dequeue_listener_async(self) -> None: def _publish_sessions_to_listener_async(self, listener: AbstractViewListener) -> None: inside_workspace = self._workspace.contains(listener.view) - scheme = urllib.parse.urlparse(listener.get_uri()).scheme + scheme = parse_uri(listener.get_uri())[0] for session in self._sessions: if session.can_handle(listener.view, scheme, capability=None, inside_workspace=inside_workspace): # debug("registering session", session.config.name, "to listener", listener) @@ -200,7 +202,7 @@ def sessions(self, view: sublime.View, capability: Optional[str] = None) -> Gene uri = view.settings().get("lsp_uri") if not isinstance(uri, str): return - scheme = urllib.parse.urlparse(uri).scheme + scheme = parse_uri(uri)[0] for session in sessions: if session.can_handle(view, scheme, capability, inside_workspace): yield session diff --git a/plugin/diagnostics.py b/plugin/diagnostics.py index 6c917ff40..0e0ea5831 100644 --- a/plugin/diagnostics.py +++ b/plugin/diagnostics.py @@ -1,8 +1,8 @@ +from .core.constants import DIAGNOSTIC_KINDS from .core.protocol import Diagnostic from .core.protocol import DiagnosticSeverity from .core.settings import userprefs from .core.typing import List, Tuple -from .core.views import DIAGNOSTIC_KINDS from .core.views import diagnostic_severity from .core.views import format_diagnostics_for_annotation import sublime diff --git a/plugin/documents.py b/plugin/documents.py index 150a65ada..a3b3188fb 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -2,6 +2,8 @@ from .code_actions import CodeActionOrCommand from .code_actions import CodeActionsByConfigName from .completion import QueryCompletionsTask +from .core.constants import DOCUMENT_HIGHLIGHT_KIND_NAMES +from .core.constants import DOCUMENT_HIGHLIGHT_KIND_SCOPES from .core.constants import HOVER_ENABLED_KEY from .core.logging import debug from .core.open import open_in_browser @@ -38,8 +40,6 @@ from .core.url import parse_uri from .core.url import view_to_uri from .core.views import diagnostic_severity -from .core.views import DOCUMENT_HIGHLIGHT_KIND_SCOPES -from .core.views import DOCUMENT_HIGHLIGHT_KINDS from .core.views import first_selection_region from .core.views import format_code_actions_for_quick_panel from .core.views import format_diagnostic_for_html @@ -70,8 +70,16 @@ def is_regular_view(v: sublime.View) -> bool: # Not from the quick panel (CTRL+P), and not a special view like a console, output panel or find-in-files panels. - is_widget = v.settings().get('is_widget') - return not v.sheet().is_transient() and v.element() is None and not is_widget + if v.element() is not None: + return False + if v.settings().get('is_widget'): + return False + sheet = v.sheet() + if not sheet: + return False + if sheet.is_transient(): + return False + return True def previous_non_whitespace_char(view: sublime.View, pt: int) -> str: @@ -764,7 +772,7 @@ def _resolve_visible_code_lenses_async(self) -> None: # --- textDocument/documentHighlight ------------------------------------------------------------------------------- def _highlights_key(self, kind: DocumentHighlightKind, multiline: bool) -> str: - return "lsp_highlight_{}{}".format(DOCUMENT_HIGHLIGHT_KINDS[kind], "m" if multiline else "s") + return "lsp_highlight_{}{}".format(DOCUMENT_HIGHLIGHT_KIND_NAMES[kind], "m" if multiline else "s") def _clear_highlight_regions(self) -> None: for kind in [DocumentHighlightKind.Text, DocumentHighlightKind.Read, DocumentHighlightKind.Write]: diff --git a/plugin/goto_diagnostic.py b/plugin/goto_diagnostic.py index c5abbfa8a..f9d0abad7 100644 --- a/plugin/goto_diagnostic.py +++ b/plugin/goto_diagnostic.py @@ -1,3 +1,4 @@ +from .core.constants import DIAGNOSTIC_KINDS from .core.diagnostics_storage import is_severity_included from .core.diagnostics_storage import ParsedUri from .core.input_handlers import PreselectedListInputHandler @@ -13,8 +14,8 @@ from .core.settings import userprefs from .core.types import ClientConfig from .core.typing import Dict, Iterator, List, Optional, Tuple, Union +from .core.typing import cast from .core.url import parse_uri, unparse_uri -from .core.views import DIAGNOSTIC_KINDS from .core.views import diagnostic_severity from .core.views import format_diagnostic_for_html from .core.views import format_diagnostic_source_and_code @@ -152,8 +153,10 @@ def description(self, value: DocumentUri, text: str) -> str: return self._project_path(parse_uri(value)) def cancel(self) -> None: - if self._preview is not None and self._preview.sheet().is_transient(): - self._preview.close() + if self._preview is not None: + sheet = self._preview.sheet() + if sheet and sheet.is_transient(): + self._preview.close() self.window.focus_view(self.view) def preview(self, value: Optional[DocumentUri]) -> str: @@ -205,7 +208,7 @@ def list_items(self) -> List[sublime.ListInputItem]: text = "{}: {}".format(format_severity(diagnostic_severity(diagnostic)), first_line) annotation = format_diagnostic_source_and_code(diagnostic) kind = DIAGNOSTIC_KINDS[diagnostic_severity(diagnostic)] - list_items.append(sublime.ListInputItem(text, (i, diagnostic), annotation=annotation, kind=kind)) + list_items.append(sublime.ListInputItem(text, [i, diagnostic], annotation=annotation, kind=kind)) return list_items def placeholder(self) -> str: @@ -214,10 +217,11 @@ def placeholder(self) -> str: def next_input(self, args: dict) -> Optional[sublime_plugin.CommandInputHandler]: return None if args.get("diagnostic") else sublime_plugin.BackInputHandler() # type: ignore - def confirm(self, value: Optional[Tuple[int, Diagnostic]]) -> None: + def confirm(self, value: Optional[list]) -> None: if not value: return - i, diagnostic = value + i = cast(int, value[0]) + diagnostic = cast(Diagnostic, value[1]) session = self.sessions[i] location = self._get_location(diagnostic) scheme, _ = self.parsed_uri @@ -227,14 +231,17 @@ def confirm(self, value: Optional[Tuple[int, Diagnostic]]) -> None: sublime.set_timeout_async(functools.partial(session.open_location_async, location)) def cancel(self) -> None: - if self._preview is not None and self._preview.sheet().is_transient(): - self._preview.close() + if self._preview is not None: + sheet = self._preview.sheet() + if sheet and sheet.is_transient(): + self._preview.close() self.window.focus_view(self.view) - def preview(self, value: Optional[Tuple[int, Diagnostic]]) -> Union[str, sublime.Html]: + def preview(self, value: Optional[list]) -> Union[str, sublime.Html]: if not value: return "" - i, diagnostic = value + i = cast(int, value[0]) + diagnostic = cast(Diagnostic, value[1]) session = self.sessions[i] base_dir = None scheme, path = self.parsed_uri diff --git a/plugin/hierarchy.py b/plugin/hierarchy.py index 9ff07ae93..9f7f2e260 100644 --- a/plugin/hierarchy.py +++ b/plugin/hierarchy.py @@ -1,3 +1,4 @@ +from .core.constants import SYMBOL_KINDS from .core.paths import simple_path from .core.promise import Promise from .core.protocol import CallHierarchyIncomingCall @@ -13,14 +14,13 @@ from .core.registry import get_position from .core.registry import LspTextCommand from .core.registry import LspWindowCommand -from .core.registry import new_tree_view_sheet from .core.sessions import Session +from .core.tree_view import new_tree_view_sheet from .core.tree_view import TreeDataProvider from .core.tree_view import TreeItem from .core.typing import Callable, List, Optional, TypedDict, Union from .core.typing import cast from .core.views import make_command_link -from .core.views import SYMBOL_KINDS from .core.views import text_document_position_params from abc import ABCMeta from abc import abstractmethod diff --git a/plugin/hover.py b/plugin/hover.py index 3b82e91fc..51b72bdda 100644 --- a/plugin/hover.py +++ b/plugin/hover.py @@ -369,10 +369,10 @@ def on_select(targets: List[str], idx: int) -> None: position = {"line": row, "character": col_utf16} # type: Position r = {"start": position, "end": position} # type: Range sublime.set_timeout_async(partial(session.open_uri_async, uri, r)) - elif urlparse(href).scheme.lower() not in ("", "http", "https"): - sublime.set_timeout_async(partial(self.try_open_custom_uri_async, href)) - else: + elif parse_uri(href)[0].lower() in ("", "http", "https"): open_in_browser(href) + else: + sublime.set_timeout_async(partial(self.try_open_custom_uri_async, href)) def handle_code_action_select(self, config_name: str, actions: List[CodeActionOrCommand], index: int) -> None: if index == -1: diff --git a/plugin/locationpicker.py b/plugin/locationpicker.py index 16bac6662..2802d5118 100644 --- a/plugin/locationpicker.py +++ b/plugin/locationpicker.py @@ -1,3 +1,4 @@ +from .core.constants import SublimeKind from .core.logging import debug from .core.protocol import DocumentUri from .core.protocol import Location @@ -7,7 +8,6 @@ from .core.typing import Union, List, Optional, Tuple from .core.views import get_uri_and_position_from_location from .core.views import location_to_human_readable -from .core.views import SublimeKind from .core.views import to_encoded_filename from urllib.request import url2pathname import functools diff --git a/plugin/references.py b/plugin/references.py index 35961378b..ecae586a5 100644 --- a/plugin/references.py +++ b/plugin/references.py @@ -190,7 +190,7 @@ def _show_references_in_output_panel(self, word: str, session: Session, location }) # highlight all word occurrences regions = panel.find_all(r"\b{}\b".format(word)) - panel.add_regions('ReferenceHighlight', regions, 'comment', flags=sublime.DRAW_OUTLINED) + panel.add_regions('ReferenceHighlight', regions, 'comment', flags=sublime.DRAW_NO_FILL) def _get_relative_path(base_dir: Optional[str], file_path: str) -> str: diff --git a/plugin/session_view.py b/plugin/session_view.py index 0e775acb9..addfd68ae 100644 --- a/plugin/session_view.py +++ b/plugin/session_view.py @@ -1,6 +1,7 @@ from .code_lens import CodeLensView from .code_lens import LspToggleCodeLensesCommand from .core.active_request import ActiveRequest +from .core.constants import DOCUMENT_HIGHLIGHT_KIND_NAMES from .core.constants import HOVER_ENABLED_KEY from .core.constants import HOVER_HIGHLIGHT_KEY from .core.constants import HOVER_PROVIDER_COUNT_KEY @@ -135,13 +136,12 @@ def _initialize_region_keys(self) -> None: r = [sublime.Region(0, 0)] document_highlight_style = userprefs().document_highlight_style hover_highlight_style = userprefs().hover_highlight_style - document_highlight_kinds = ["text", "read", "write"] line_modes = ["m", "s"] self.view.add_regions(self.CODE_ACTIONS_KEY, r) # code actions lightbulb icon should always be on top for key in range(1, 100): self.view.add_regions("lsp_semantic_{}".format(key), r) if document_highlight_style in ("background", "fill"): - for kind in document_highlight_kinds: + for kind in DOCUMENT_HIGHLIGHT_KIND_NAMES.values(): for mode in line_modes: self.view.add_regions("lsp_highlight_{}{}".format(kind, mode), r) if hover_highlight_style in ("background", "fill"): @@ -158,7 +158,7 @@ def _initialize_region_keys(self) -> None: for mode in line_modes: self.view.add_regions("lsp{}d{}{}_underline".format(self.session.config.name, mode, severity), r) if document_highlight_style in ("underline", "stippled"): - for kind in document_highlight_kinds: + for kind in DOCUMENT_HIGHLIGHT_KIND_NAMES.values(): for mode in line_modes: self.view.add_regions("lsp_highlight_{}{}".format(kind, mode), r) if hover_highlight_style in ("underline", "stippled"): @@ -255,7 +255,8 @@ def get_language_id(self) -> Optional[str]: return listener.get_language_id() if listener else None def get_view_for_group(self, group: int) -> Optional[sublime.View]: - return self.view if self.view.sheet().group() == group else None + sheet = self.view.sheet() + return self.view if sheet and sheet.group() == group else None def get_capability_async(self, capability_path: str) -> Optional[Any]: return self.session_buffer.get_capability(capability_path) diff --git a/plugin/symbols.py b/plugin/symbols.py index 7beeef3b9..8007b6504 100644 --- a/plugin/symbols.py +++ b/plugin/symbols.py @@ -1,3 +1,5 @@ +from .core.constants import SublimeKind +from .core.constants import SYMBOL_KINDS from .core.input_handlers import DynamicListInputHandler from .core.input_handlers import PreselectedListInputHandler from .core.promise import Promise @@ -18,7 +20,6 @@ from .core.typing import cast from .core.views import offset_to_point from .core.views import range_to_region -from .core.views import SYMBOL_KINDS from .core.views import text_document_identifier import functools import os diff --git a/stubs/sublime.pyi b/stubs/sublime.pyi index 20ba5337b..2c3395bc3 100644 --- a/stubs/sublime.pyi +++ b/stubs/sublime.pyi @@ -1,598 +1,1367 @@ -# Stubs for sublime (Python 3.5) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - -from typing import Any, Callable, Dict, Iterator, List, Optional, Reversible, Sequence, Tuple, Union - - -class _LogWriter: - def flush(self) -> None: - ... - - def write(self, s: str) -> None: - ... - - -HOVER_TEXT = ... # type: int -HOVER_GUTTER = ... # type: int -HOVER_MARGIN = ... # type: int -ENCODED_POSITION = ... # type: int -TRANSIENT = ... # type: int -SEMI_TRANSIENT = ... # type: int -FORCE_GROUP = ... # type: int -ADD_TO_SELECTION = ... # type: int -REPLACE_MRU = ... # type: int -CLEAR_TO_RIGHT = ... # type: int -IGNORECASE = ... # type: int -LITERAL = ... # type: int -MONOSPACE_FONT = ... # type: int -KEEP_OPEN_ON_FOCUS_LOST = ... # type: int -HTML = ... # type: int -COOPERATE_WITH_AUTO_COMPLETE = ... # type: int -HIDE_ON_MOUSE_MOVE = ... # type: int -HIDE_ON_MOUSE_MOVE_AWAY = ... # type: int -KEEP_ON_SELECTION_MODIFIED = ... # type: int -DRAW_EMPTY = ... # type: int -HIDE_ON_MINIMAP = ... # type: int -DRAW_EMPTY_AS_OVERWRITE = ... # type: int -PERSISTENT = ... # type: int -DRAW_OUTLINED = ... # type: int -DRAW_NO_FILL = ... # type: int -DRAW_NO_OUTLINE = ... # type: int -DRAW_SOLID_UNDERLINE = ... # type: int -DRAW_STIPPLED_UNDERLINE = ... # type: int -DRAW_SQUIGGLY_UNDERLINE = ... # type: int -HIDDEN = ... # type: int -OP_EQUAL = ... # type: int -OP_NOT_EQUAL = ... # type: int -OP_REGEX_MATCH = ... # type: int -OP_NOT_REGEX_MATCH = ... # type: int -OP_REGEX_CONTAINS = ... # type: int -OP_NOT_REGEX_CONTAINS = ... # type: int -CLASS_WORD_START = ... # type: int -CLASS_WORD_END = ... # type: int -CLASS_PUNCTUATION_START = ... # type: int -CLASS_PUNCTUATION_END = ... # type: int -CLASS_SUB_WORD_START = ... # type: int -CLASS_SUB_WORD_END = ... # type: int -CLASS_LINE_START = ... # type: int -CLASS_LINE_END = ... # type: int -CLASS_EMPTY_LINE = ... # type: int -INHIBIT_WORD_COMPLETIONS = ... # type: int -INHIBIT_EXPLICIT_COMPLETIONS = ... # type: int -INHIBIT_REORDER = ... # type: int -DYNAMIC_COMPLETIONS = ... # type: int -COMPLETION_FLAG_KEEP_PREFIX = ... # type: int -COMPLETION_FORMAT_COMMAND = ... # type: int -DIALOG_CANCEL = ... # type: int -DIALOG_YES = ... # type: int -DIALOG_NO = ... # type: int -UI_ELEMENT_SIDE_BAR = ... # type: int -UI_ELEMENT_MINIMAP = ... # type: int -UI_ELEMENT_TABS = ... # type: int -UI_ELEMENT_STATUS_BAR = ... # type: int -UI_ELEMENT_MENU = ... # type: int -UI_ELEMENT_OPEN_FILES = ... # type: int -LAYOUT_INLINE = ... # type: int -LAYOUT_BELOW = ... # type: int -LAYOUT_BLOCK = ... # type: int -KIND_ID_AMBIGUOUS = ... # type: int -KIND_ID_KEYWORD = ... # type: int -KIND_ID_TYPE = ... # type: int -KIND_ID_COLOR_DARK = ... # type: int -KIND_ID_COLOR_LIGHT = ... # type: int -KIND_ID_COLOR_BLUISH = ... # type: int -KIND_ID_COLOR_CYANISH = ... # type: int -KIND_ID_COLOR_GREENISH = ... # type: int -KIND_ID_COLOR_ORANGISH = ... # type: int -KIND_ID_COLOR_PINKISH = ... # type: int -KIND_ID_COLOR_PURPLISH = ... # type: int -KIND_ID_COLOR_REDISH = ... # type: int -KIND_ID_COLOR_YELLOWISH = ... # type: int -KIND_ID_FUNCTION = ... # type: int -KIND_ID_NAMESPACE = ... # type: int -KIND_ID_NAVIGATION = ... # type: int -KIND_ID_MARKUP = ... # type: int -KIND_ID_VARIABLE = ... # type: int -KIND_ID_SNIPPET = ... # type: int -KIND_AMBIGUOUS = ... # type: Tuple[int, str, str] -KIND_KEYWORD = ... # type: Tuple[int, str, str] -KIND_TYPE = ... # type: Tuple[int, str, str] -KIND_FUNCTION = ... # type: Tuple[int, str, str] -KIND_NAMESPACE = ... # type: Tuple[int, str, str] -KIND_NAVIGATION = ... # type: Tuple[int, str, str] -KIND_MARKUP = ... # type: Tuple[int, str, str] -KIND_VARIABLE = ... # type: Tuple[int, str, str] -KIND_SNIPPET = ... # type: Tuple[int, str, str] -COMPLETION_FORMAT_TEXT = ... # type: int -COMPLETION_FORMAT_SNIPPET = ... # type: int -WANT_EVENT = ... # type: int +# Stubs for sublime.py (Python 3.3 API Environment) +from typing import Any, Callable, Dict, Iterable, Iterator, List, Literal, Optional, Reversible, Sequence, Tuple +from typing_extensions import deprecated + + +HOVER_TEXT: Literal[1] +"""The mouse is hovered over the text.""" +HOVER_GUTTER: Literal[2] +"""The mouse is hovered over the gutter.""" +HOVER_MARGIN: Literal[3] +"""The mouse is hovered in the white space to the right of a line.""" + +ENCODED_POSITION: Literal[1] +"""Indicates that the file name should be searched for a `:row` or `:row:col` suffix.""" +TRANSIENT: Literal[4] +"""Open the file as a preview only: it won't have a tab assigned it until modified.""" +FORCE_GROUP: Literal[8] +""" +Don't select the file if it is open in a different group. Instead make a new clone of that file in the desired group. +""" +SEMI_TRANSIENT: Literal[16] +""" +If a sheet is newly created, it will be set to semi-transient. Semi-transient sheets generally replace other +semi-transient sheets. This is used for the side-bar preview. Only valid with `ADD_TO_SELECTION` or `REPLACE_MRU`. +""" +ADD_TO_SELECTION: Literal[32] +"""Add the file to the currently selected sheets in the group.""" +REPLACE_MRU: Literal[64] +"""Causes the sheet to replace the most-recently used sheet in the current sheet selection.""" +CLEAR_TO_RIGHT: Literal[128] +""" +All currently selected sheets to the right of the most-recently used sheet will be unselected before opening the file. +Only valid in combination with `ADD_TO_SELECTION`. +""" +FORCE_CLONE: Literal[256] +"""Don't select the file if it is open. Instead make a new clone of that file in the desired group.""" + +LITERAL: Literal[1] +"""Whether the find pattern should be matched literally or as a regex.""" +IGNORECASE: Literal[2] +"""Whether case should be considered when matching the find pattern.""" +WHOLEWORD: Literal[4] +"""Whether to only match whole words.""" +REVERSE: Literal[8] +"""Whether to search backwards.""" +WRAP: Literal[16] +"""Whether to wrap around once the end is reached.""" + +MONOSPACE_FONT: Literal[1] +"""Use a monospace font.""" +KEEP_OPEN_ON_FOCUS_LOST: Literal[2] +"""Keep the quick panel open if the window loses input focus.""" +WANT_EVENT: Literal[4] +"""Pass a second parameter to the `on_done` callback, a `Event`.""" + +HTML: Literal[1] +COOPERATE_WITH_AUTO_COMPLETE: Literal[2] +"""Causes the popup to display next to the auto complete menu.""" +HIDE_ON_MOUSE_MOVE: Literal[4] +"""Causes the popup to hide when the mouse is moved, clicked or scrolled.""" +HIDE_ON_MOUSE_MOVE_AWAY: Literal[8] +"""Causes the popup to hide when the mouse is moved (unless towards the popup), or when clicked or scrolled.""" +KEEP_ON_SELECTION_MODIFIED: Literal[16] +"""Prevent the popup from hiding when the selection is modified.""" +HIDE_ON_CHARACTER_EVENT: Literal[32] +"""Hide the popup when a character is typed.""" + +DRAW_EMPTY: Literal[1] +"""Draw empty regions with a vertical bar. By default, they aren't drawn at all.""" +HIDE_ON_MINIMAP: Literal[2] +"""Don't show the regions on the minimap.""" +DRAW_EMPTY_AS_OVERWRITE: Literal[4] +"""Draw empty regions with a horizontal bar instead of a vertical one.""" +PERSISTENT: Literal[16] +"""Save the regions in the session.""" +DRAW_NO_FILL: Literal[32] +"""Disable filling the regions, leaving only the outline.""" +HIDDEN: Literal[128] +"""Don't draw the regions.""" +DRAW_NO_OUTLINE: Literal[256] +"""Disable drawing the outline of the regions.""" +DRAW_SOLID_UNDERLINE: Literal[512] +"""Draw a solid underline below the regions.""" +DRAW_STIPPLED_UNDERLINE: Literal[1024] +"""Draw a stippled underline below the regions.""" +DRAW_SQUIGGLY_UNDERLINE: Literal[2048] +"""Draw a squiggly underline below the regions.""" +NO_UNDO: Literal[8192] + +OP_EQUAL: Literal[0] +OP_NOT_EQUAL: Literal[1] +OP_REGEX_MATCH: Literal[2] +OP_NOT_REGEX_MATCH: Literal[3] +OP_REGEX_CONTAINS: Literal[4] +OP_NOT_REGEX_CONTAINS: Literal[5] +CLASS_WORD_START: Literal[1] +"""The point is the start of a word.""" +CLASS_WORD_END: Literal[2] +"""The point is the end of a word.""" +CLASS_PUNCTUATION_START: Literal[4] +"""The point is the start of a sequence of punctuation characters.""" +CLASS_PUNCTUATION_END: Literal[8] +"""The point is the end of a sequence of punctuation characters.""" +CLASS_SUB_WORD_START: Literal[16] +"""The point is the start of a sub-word.""" +CLASS_SUB_WORD_END: Literal[32] +"""The point is the end of a sub-word.""" +CLASS_LINE_START: Literal[64] +"""The point is the start of a line.""" +CLASS_LINE_END: Literal[128] +"""The point is the end of a line.""" +CLASS_EMPTY_LINE: Literal[256] +"""The point is an empty line.""" + +INHIBIT_WORD_COMPLETIONS: Literal[8] +"""Prevent Sublime Text from showing completions based on the contents of the view.""" +INHIBIT_EXPLICIT_COMPLETIONS: Literal[16] +"""Prevent Sublime Text from showing completions based on `.sublime-completions` files.""" +DYNAMIC_COMPLETIONS: Literal[32] +"""If completions should be re-queried as the user types.""" +INHIBIT_REORDER: Literal[128] +"""Prevent Sublime Text from changing the completion order.""" + +DIALOG_CANCEL: Literal[0] +DIALOG_YES: Literal[1] +DIALOG_NO: Literal[2] + +LAYOUT_INLINE: Literal[0] +"""The phantom is positioned inline with the text at the beginning of its `Region`.""" +LAYOUT_BELOW: Literal[1] +"""The phantom is positioned below the line, left-aligned with the beginning of its `Region`.""" +LAYOUT_BLOCK: Literal[2] +"""The phantom is positioned below the line, left-aligned with the beginning of the line.""" + +KIND_ID_AMBIGUOUS: Literal[0] +KIND_ID_KEYWORD: Literal[1] +KIND_ID_TYPE: Literal[2] +KIND_ID_FUNCTION: Literal[3] +KIND_ID_NAMESPACE: Literal[4] +KIND_ID_NAVIGATION: Literal[5] +KIND_ID_MARKUP: Literal[6] +KIND_ID_VARIABLE: Literal[7] +KIND_ID_SNIPPET: Literal[8] + +KIND_ID_COLOR_REDISH: Literal[9] +KIND_ID_COLOR_ORANGISH: Literal[10] +KIND_ID_COLOR_YELLOWISH: Literal[11] +KIND_ID_COLOR_GREENISH: Literal[12] +KIND_ID_COLOR_CYANISH: Literal[13] +KIND_ID_COLOR_BLUISH: Literal[14] +KIND_ID_COLOR_PURPLISH: Literal[15] +KIND_ID_COLOR_PINKISH: Literal[16] +KIND_ID_COLOR_DARK: Literal[17] +KIND_ID_COLOR_LIGHT: Literal[18] + +KIND_AMBIGUOUS: Tuple[int, str, str] +KIND_KEYWORD: Tuple[int, str, str] +KIND_TYPE: Tuple[int, str, str] +KIND_FUNCTION: Tuple[int, str, str] +KIND_NAMESPACE: Tuple[int, str, str] +KIND_NAVIGATION: Tuple[int, str, str] +KIND_MARKUP: Tuple[int, str, str] +KIND_VARIABLE: Tuple[int, str, str] +KIND_SNIPPET: Tuple[int, str, str] + +SYMBOL_SOURCE_ANY: Literal[0] +"""Use any source - both the index and open files.""" +SYMBOL_SOURCE_INDEX: Literal[1] +"""Use the index created when scanning through files in a project folder.""" +SYMBOL_SOURCE_OPEN_FILES: Literal[2] +"""Use the open files, unsaved or otherwise.""" + +SYMBOL_TYPE_ANY: Literal[0] +"""Any symbol type - both definitions and references.""" +SYMBOL_TYPE_DEFINITION: Literal[1] +"""Only definitions.""" +SYMBOL_TYPE_REFERENCE: Literal[2] +"""Only references.""" + +COMPLETION_FORMAT_TEXT: Literal[0] +"""Plain text, upon completing the text is inserted verbatim.""" +COMPLETION_FORMAT_SNIPPET: Literal[1] +"""A snippet, with `$` variables.""" +COMPLETION_FORMAT_COMMAND: Literal[2] +"""A command string, in the format returned by `format_command()`.""" + +COMPLETION_FLAG_KEEP_PREFIX: Literal[1] -class Settings: - settings_id = ... # type: int +def version() -> str: + """ + The version number. + """ + ... - def __init__(self, id: int) -> None: - ... - def get(self, key: str, default: Optional[Any] = ...) -> Optional[Any]: - ... +def platform() -> Literal["osx", "linux", "windows"]: + """ + The platform which the plugin is being run on. + """ + ... - def has(self, key: str) -> bool: - ... - def set(self, key: str, value: Any) -> None: - ... +def arch() -> Literal["x32", "x64", "arm64"]: + """ + The CPU architecture. + """ + ... - def erase(self, key: str) -> None: - ... - def add_on_change(self, tag: str, callback: Callable[[], None]) -> None: - ... +def channel() -> Literal["dev", "stable"]: + """ + The release channel of this build of Sublime Text. + """ + ... - def clear_on_change(self, tag: str) -> None: - ... +def executable_path() -> str: + """ + The path to the main Sublime Text executable. + """ + ... -def version() -> str: + +def executable_hash() -> Tuple[str, str, str]: + """ + A tuple uniquely identifying the installation of Sublime Text. + """ ... -def platform() -> str: +def packages_path() -> str: + """ + The path to the "Packages" folder. + """ ... -def arch() -> str: +def installed_packages_path() -> str: + """ + The path to the "Installed Packages" folder. + """ ... -def channel() -> str: +def cache_path() -> str: + """ + The path where Sublime Text stores cache files. + """ ... -def executable_path() -> str: +def status_message(msg: str) -> None: + """ + Show a message in the status bar. + """ ... -def executable_hash() -> str: +def error_message(msg: str) -> None: + """ + Display an error dialog. + """ ... -def packages_path() -> str: +def message_dialog(msg: str) -> None: + """ + Display a message dialog. + """ ... -def installed_packages_path() -> str: +def ok_cancel_dialog(msg: str, ok_title: str = ..., title: str = ...) -> bool: + """ + Show a popup dialog with an "ok" and "cancel" button. + + - `msg` - The message to show in the dialog. + - `ok_title` - Optional replacement string for the "ok" button. + - `title` - Optional title for the dialog. Note Linux and macOS do not have a title in their dialog. + + Returns `True` if the user presses the `ok` button, `False` otherwise. + """ ... -def cache_path() -> str: +def yes_no_cancel_dialog(msg: str, yes_title: str = ..., no_title: str = ..., title: str = ...) -> int: + """ + Show a popup dialog with a "yes", "no" and "cancel" button. + + - `msg` - The message to show in the dialog. + - `yes_title` - Optional replacement string for the "yes" button. + - `no_title` - Optional replacement string for the "no" button. + - `title` - Optional title for the dialog. Note Linux and macOS do not have a title in their dialog. + + Returns `DIALOG_YES`, `DIALOG_NO` or `DIALOG_CANCEL`. + """ ... -def status_message(msg: str) -> None: +def open_dialog( + callback: Callable[[str | List[str] | None], None], + file_types: List[Tuple[str, List[str]]] = ..., + directory: str | None = ..., + multi_select: bool = ..., + allow_folders: bool = ... +) -> None: + """ + Show the open file dialog. + + - `callback` - Called with selected path(s) or `None` once the dialog is closed. + - `file_types` - A list of allowed file types, consisting of a description and a list of allowed extensions. + - `directory` - The directory the dialog should start in. Will use the virtual working directory if not provided. + - `multi_select` - Whether to allow selecting multiple files. When `True` the callback will be called with a list. + - `allow_folders` - Whether to also allow selecting folders. Only works on macOS. If you only want to select folders + use `select_folder_dialog`. + """ ... -def error_message(msg: str) -> None: +def save_dialog( + callback: Callable[[str | None], None], + file_types: List[Tuple[str, List[str]]] = ..., + directory: str | None = ..., + name: str | None = ..., + extension: str | None = ..., +) -> None: + """ + Show the save file dialog. + + - `callback` - Called with selected path or `None` once open dialog is closed. + - `file_types` - A list of allowed file types, consisting of a description and a list of allowed extensions. + - `directory` - The directory the dialog should start in. Will use the virtual working directory if not provided. + - `name` - The default name of the file in the save dialog. + - `extension` - The default extension used in the save dialog. + """ ... -def message_dialog(msg: str) -> None: +def select_folder_dialog( + callback: Callable[[str | List[str] | None], None], + directory: str | None = ..., + multi_select: bool = ..., +) -> None: + """ + Show the select folder dialog. + + - `callback` - Called with selected path(s) or `None` once open dialog is closed. + - `directory` - The directory the dialog should start in. Will use the virtual working directory if not provided. + - `multi_select` - Whether to allow selecting multiple folders. When `True` the callback will be called with a list. + """ + ... + + +def choose_font_dialog( + callback: Callable[[Dict[str, Any] | None], None], + default: Dict[str, Any] | None = ... +) -> None: + """ + Show a dialog for selecting a font. + + - `callback` - Called with the font options, matching the format used in settings + (eg. `{ "font_face": "monospace" }`). May be called more than once, or will be called with `None` if the dialog + is cancelled. + - `default` - The default values to select/return. Same format as the argument passed to `callback`. + """ + ... + + +def run_command(cmd: str, args: Dict[str, Any] | None = ...) -> None: + """ + Runs the named `ApplicationCommand` with the (optional) given `args`. + """ + ... + + +def format_command(cmd: str, args: Dict[str, Any] | None = ...) -> str: + """ + Creates a "command string" from a str cmd name, and an optional dict of args. This is used when constructing a + command-based `CompletionItem`. + """ ... -def ok_cancel_dialog(msg: str, ok_title: str = ...) -> bool: +def html_format_command(cmd: str, args: Dict[str, Any] | None = ...) -> str: + """ + Creates an escaped "command string" for usage in HTML popups and sheets. + """ ... -def yes_no_cancel_dialog(msg: str, yes_title: str = ..., no_title: str = ...) -> int: +def command_url(cmd: str, args: Dict[str, Any] | None = ...) -> str: + """ + Creates a `subl:` protocol URL for executing a command in a minihtml link. + """ ... -def run_command(cmd: str, args: Optional[Any] = ...) -> None: +def get_clipboard_async(callback: Callable[[str], None], size_limit: int = ...) -> None: + """ + Calls `callback` with the contents of the clipboard. For performance reasons if the size of the clipboard content is + bigger than `size_limit`, an empty string will be returned. + """ ... +@deprecated("Use get_clipboard_async() when possible") def get_clipboard(size_limit: int = ...) -> str: + """ + Returns the content of the clipboard. For performance reasons if the size of the clipboard content is bigger than + size_limit, an empty string will be returned. + """ ... def set_clipboard(text: str) -> None: + """ + Sets the contents of the clipboard. + """ ... -def log_commands(flag: bool) -> None: +def log_commands(flag: bool | None = ...) -> None: + """ + Controls command logging. If enabled, all commands run from key bindings and the menu will be logged to the console. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ ... -def log_input(flag: bool) -> None: +def get_log_commands() -> bool: + """ + Returns whether command logging is enabled. + """ ... -def log_result_regex(flag: bool) -> None: +def log_input(flag: bool | None = ...) -> None: + """ + Control whether all key presses will be logged to the console. Use this to find the names of certain keys on the + keyboard. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ + ... + + +def get_log_input() -> bool: + """ + Returns whether input logging is enabled. + """ + ... + + +def log_fps(flag: bool | None = ...) -> None: + """ + Control whether rendering timings like frames per second get logged. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ + ... + + +def get_log_fps() -> bool: + """ + Returns whether fps logging is enabled. + """ + ... + + +def log_result_regex(flag: bool | None = ...) -> None: + """ + Control whether result regex logging is enabled. Use this to debug `"file_regex"` and `"line_regex"` in build + systems. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ + ... + + +def get_log_result_regex() -> bool: + """ + Returns whether result regex logging is enabled. + """ + ... + + +def log_indexing(flag: bool | None = ...) -> None: + """ + Control whether indexing logs are printed to the console. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ + ... + + +def get_log_indexing() -> bool: + """ + Returns whether indexing logging is enabled. + """ ... -def log_indexing(flag: bool) -> None: +def log_build_systems(flag: bool | None = ...) -> None: + """ + Control whether build system logs are printed to the console. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ ... -def log_build_systems(flag: bool) -> None: +def get_log_build_systems() -> bool: + """ + Returns whether build system logging is enabled. + """ + ... + + +def log_control_tree(flag: bool | None = ...) -> None: + """ + Control whether control tree logging is enabled. When enabled clicking with Ctrl+Alt will log the control tree under + the mouse to the console. + + - `flag` - Whether to log. Passing `None` toggles logging. + """ + ... + + +def get_log_control_tree() -> bool: + """ + Returns whether control tree logging is enabled. + """ + ... + + +def ui_info() -> Dict[str, Any]: + """ + Information about the user interface including top-level keys `system`, `theme` and `color_scheme`. + """ ... def score_selector(scope_name: str, selector: str) -> int: + """ + Match the `selector` against the given `scope_name`, returning a score for how well they match. + + A score of `0` means no match, above `0` means a match. Different selectors may be compared against the same scope: + a higher score means the selector is a better match for the scope. + """ ... def load_resource(name: str) -> str: + """ + Loads the given resource. The name should be in the format "Packages/Default/Main.sublime-menu". + + Raises `FileNotFoundError` if resource is not found. + """ ... def load_binary_resource(name: str) -> bytes: + """ + Loads the given binary resource. The name should be in the format "Packages/Default/Main.sublime-menu". + + Raises `FileNotFoundError` if resource is not found. + """ ... def find_resources(pattern: str) -> Sequence[str]: + """Finds resources whose file name matches the given glob pattern.""" ... -def encode_value(val: Any, pretty: bool = ...) -> str: +def encode_value(val: Any, pretty: bool = ..., update_text: str = ...) -> str: + """ + Encode a JSON compatible `Value` into a string representation. + + - `pretty` - Whether the result should include newlines and be indented. + - `update_text` - Incrementally update the value encoded in this text. Best effort is made to preserve the contents + of `update_text` - comments, indentation, etc. This is the same algorithm used to change settings values. + Providing this makes `pretty` have no effect. + """ ... def decode_value(data: str) -> Any: + """ + Decode a JSON string into an object. Note that comments and trailing commas are allowed. + + Raises `ValueError` if the string is not valid JSON. + """ ... -def expand_variables(val: Any, variables: dict) -> Any: +def expand_variables(val: Any, variables: Dict[str, str]) -> Any: + """ + Expands any variables in `val` using the variables defined in the dictionary `variables`. `val` may also be a list + or dict, in which case the structure will be recursively expanded. Strings should use snippet syntax, for example: + + ```python + expand_variables("Hello, ${name}", {"name": "Foo"}) + ``` + """ ... def load_settings(base_name: str) -> Settings: + """ + Loads the named settings. The name should include a file name and extension, but not a path. The packages will be + searched for files matching the base_name, and the results will be collated into the settings object. + + Subsequent calls to `load_settings` with the base_name will return the same object, and not load the settings from + disk again. + """ ... def save_settings(base_name: str) -> None: + """ + Flush any in-memory changes to the named settings object to disk. + """ ... def set_timeout(f: Callable[[], Any], timeout_ms: int = ...) -> None: + """ + Schedules a function to be called in the future. Sublime Text will block while the function is running. + """ ... def set_timeout_async(f: Callable[[], Any], timeout_ms: int = ...) -> None: + """ + Schedules a function to be called in the future. The function will be called in a worker thread, and Sublime Text + will not block while the function is running. + """ ... -def active_window() -> 'Window': +def active_window() -> Window: + """ + The most recently used `Window`. + """ ... -def windows() -> 'Sequence[Window]': +def windows() -> List[Window]: + """ + A list of all the open windows. + """ ... -def get_macro() -> Sequence[dict]: +def get_macro() -> List[Dict[str, Any]]: + """ + A list of the commands and args that compromise the currently recorded macro. Each dict will contain the keys + `"command"` and `"args"`. + """ ... -def syntax_from_path(syntax_path: str) -> Optional[Syntax]: +def project_history() -> List[str]: + """ + A list of most recently opened workspaces. Sublime-project files with the same name are listed in place of + sublime-workspace files. + """ ... -def command_url(cmd: str, args: Optional[dict] = ...) -> str: +def folder_history() -> List[str]: + """ + A list of recent folders added to sublime projects. + """ ... -class Syntax: - path = ... # type: str - name = ... # type: str - hidden = ... # type: bool - scope = ... # type: str +class Window: + window_id: int + settings_object: Settings + template_settings_object: Settings - def __init__(self, path: str, name: str, hidden: bool, scope: str) -> None: + def __init__(self, id: int) -> None: ... + def __eq__(self, other: object) -> bool: + ... -class CompletionItem: - trigger = ... # type: str - annotation = ... # type: str - completion = ... # type: str - completion_format = ... # type: int - kind = ... # type: Tuple[int, str, str] - details = ... # type: str - flags = ... # type: int + def __bool__(self) -> bool: + ... - def __init__( - self, - trigger: str, - annotation: str = "", - completion: str = "", - completion_format: int = COMPLETION_FORMAT_TEXT, - kind: Tuple[int, str, str] = KIND_AMBIGUOUS, - details: str = "") -> None: + def id(self) -> int: + """ + A number that uniquely identifies this window. + """ ... - @classmethod - def snippet_completion( - cls, - trigger: str, - snippet: str, - annotation: str = " ", - kind: Tuple[int, str, str] = KIND_SNIPPET, - details: str = "") -> 'CompletionItem': + def is_valid(self) -> bool: + """ + Check whether this window is still valid. Will return `False` for a closed window, for example. + """ ... - @classmethod - def command_completion(cls, - trigger: str, - command: str, - args: dict = {}, - annotation: str = "", - kind: Tuple[int, str, str] = KIND_AMBIGUOUS, - details: str = "" - ) -> 'CompletionItem': + def hwnd(self): + """ + A platform specific window handle. Windows only. + """ ... + def active_sheet(self) -> Sheet | None: + """ + The currently focused `Sheet`. + """ + ... -class CompletionList: - def set_completions(self, completions: List[CompletionItem], flags: int = 0) -> None: + def active_view(self) -> View | None: + """ + The currently edited `View`. + """ ... + def new_html_sheet(self, name: str, contents: str, flags: int = ..., group: int = ...) -> Sheet: + """ + Construct a sheet with HTML contents rendered using minihtml. -class Window: - window_id = ... # type: int - settings_object = ... # type: Settings - template_settings_object = ... # type: Any + - `name` - The name of the sheet to show in the tab. + - `contents` - The HTML contents of the sheet. + - `flags` - Only `TRANSIENT` and `ADD_TO_SELECTION` are allowed. + - `group` - The group to add the sheet to. `-1` for the active group. + """ + ... - def __init__(self, id: int) -> None: + def run_command(self, cmd: str, args: Dict[str, Any] | None = ...) -> None: + """ + Run the named `WindowCommand` with the (optional) given args. This method is able to run any sort of command, + dispatching the command via input focus. + """ ... - def __eq__(self, other: object) -> bool: + def new_file(self, flags: int = ..., syntax: str = ...) -> View: + """ + Create a new empty file. + + - `flags` - Either `0`, `TRANSIENT` or `ADD_TO_SELECTION`. + - `syntax` - The name of the syntax to apply to the file. + + Returns the `View` for the file. + """ ... - def __bool__(self) -> bool: + def open_file(self, fname: str, flags: int = ..., group: int = ...) -> View: + """ + Open the named file. If the file is already opened, it will be brought to the front. Note that as file loading + is asynchronous, operations on the returned view won't be possible until its `is_loading()` method returns + `False`. + + - `fname` - The path to the file to open. + - `flags` + - `group` - The group to add the sheet to. `-1` for the active group. + """ ... - def id(self) -> int: + def find_open_file(self, fname: str, group: int = ...) -> View | None: + """ + Find a opened file by file name. + + - `fname` - The path to the file to open. + - `group` - The group in which to search for the file. `-1` for any group. + + Returns the `View` to the file or `None` if the file isn't open. + """ ... - def is_valid(self) -> bool: + def file_history(self) -> List[str]: + """ + Get the list of previously opened files. This is the same list as File > Open Recent. + """ ... - # def hwnd(self): ... - def active_sheet(self) -> 'Sheet': + def num_groups(self) -> int: + """ + The number of view groups in the window. + """ ... - def active_view(self) -> 'Optional[View]': + def active_group(self) -> int: + """ + The index of the currently selected group. + """ ... - def new_html_sheet(self, name: str, contents: str, flags: int = ..., group: int = ...) -> 'Sheet': + def focus_group(self, idx: int) -> None: + """ + Focus the specified group, making it active. + """ ... - def run_command(self, cmd: str, args: Optional[Any] = ...) -> None: + def focus_sheet(self, sheet: Sheet) -> None: + """ + Switches to the given `Sheet`. + """ ... - def new_file(self, flags: int = ..., syntax: str = ...) -> 'View': + def focus_view(self, view: View) -> None: + """ + Switches to the given `View`. + """ ... - def open_file(self, fname: str, flags: int = ..., group: int = ...) -> 'View': + def select_sheets(self, sheets: List[Sheet]) -> None: + """ + Change the selected sheets for the entire window. + """ ... - def find_open_file(self, fname: str, group: int = ...) -> 'Optional[View]': + def bring_to_front(self) -> None: + """ + Bring the window in front of any other windows. + """ ... - def num_groups(self) -> int: + def get_sheet_index(self, sheet: Sheet) -> Tuple[int, int]: + """ + The a tuple of the group and index within the group of the given `Sheet`. + """ ... - def active_group(self) -> int: + def get_view_index(self, view: View) -> Tuple[int, int]: + """ + The a tuple of the group and index within the group of the given `View`. + """ ... - def focus_group(self, idx: int) -> None: + def set_sheet_index(self, sheet: Sheet, group: int, idx: int) -> None: + """ + Move the given `Sheet` to the given `group` at the given `index`. + """ ... - def focus_sheet(self, sheet: 'Sheet') -> None: + def set_view_index(self, view: View, group: int, idx: int) -> None: + """ + Move the given `View` to the given `group` at the given `index`. + """ ... - def focus_view(self, view: 'View') -> None: + def move_sheets_to_group( + self, + sheets: List[Sheet], + group: int, + insertion_idx: int = ..., + select: bool = ... + ) -> None: + """ + Moves all provided sheets to specified group at insertion index provided. If an index is not provided defaults + to last index of the destination group. + + - `sheets` - The sheets to move. + - `group` - The index of the group to move the sheets to. + - `insertion_idx` - The point inside the group at which to insert the sheets. + - `select` - Whether the sheets should be selected after moving them. + """ ... - def select_sheets(self, sheets: 'List[Sheet]') -> None: + def sheets(self) -> List[Sheet]: + """ + All open sheets in the window. + """ ... - def get_sheet_index(self, sheet: 'Sheet') -> Tuple[int, int]: + def views(self, *, include_transient: bool = ...) -> List[View]: + """ + All open sheets in the window. + + - `include_transient` - Whether the transient sheet should be included. + """ ... - def get_view_index(self, view: 'View') -> Tuple[int, int]: + def selected_sheets(self) -> List[Sheet]: + """ + All selected sheets in the window's currently selected group. + """ ... - def set_sheet_index(self, sheet: 'Sheet', group: int, idx: int) -> None: + def selected_sheets_in_group(self, group: int) -> List[Sheet]: + """ + All selected sheets in the specified group. + """ ... - def set_view_index(self, view: 'View', group: int, idx: int) -> None: + def active_sheet_in_group(self, group: int) -> Sheet | None: + """ + The currently focused `Sheet` in the given group. + """ ... - def sheets(self) -> 'List[Sheet]': + def active_view_in_group(self, group: int) -> View | None: + """ + The currently focused `View` in the given group. + """ ... - def selected_sheets(self) -> 'List[Sheet]': + def sheets_in_group(self, group: int) -> List[Sheet]: + """ + A list of all sheets in the specified group. + """ ... - def selected_sheets_in_group(self, group: int) -> 'List[Sheet]': + def views_in_group(self, group: int) -> List[View]: + """ + A list of all views in the specified group. + """ ... - def views(self) -> 'List[View]': + def num_sheets_in_group(self, group: int) -> int: + """ + The number of sheets in the specified group. + """ ... - def active_sheet_in_group(self, group: int) -> 'Sheet': + def num_views_in_group(self, group: int) -> int: + """ + The number of views in the specified group. + """ ... - def active_view_in_group(self, group: int) -> 'Optional[View]': + def transient_sheet_in_group(self, group: int) -> Sheet | None: + """ + The transient sheet in the specified group. + """ ... - def sheets_in_group(self, group: int) -> 'List[Sheet]': + def transient_view_in_group(self, group: int) -> View | None: + """ + The transient view in the specified group. + """ ... - def views_in_group(self, group: int) -> 'List[View]': + def promote_sheet(self, sheet: Sheet) -> None: + """ + Promote the 'Sheet' parameter if semi-transient or transient. + """ ... - def transient_sheet_in_group(self, group: int) -> 'Sheet': + def layout(self): + """ + Get the group layout of the window. + """ ... - def transient_view_in_group(self, group: int) -> 'View': + @deprecated("Use layout() instead") + def get_layout(self): ... - # def layout(self): ... - # def get_layout(self): ... - # def set_layout(self, layout): ... - def create_output_panel(self, name: str, unlisted: bool = ...) -> 'View': + def set_layout(self, layout: Dict[str, Any]) -> None: + """ + Set the group layout of the window. + """ ... - def find_output_panel(self, name: str) -> 'Optional[View]': + def create_output_panel(self, name: str, unlisted: bool = ...) -> View: + """ + Find the view associated with the named output panel, creating it if required. The output panel can be shown by + running the `show_panel` window command, with the `panel` argument set to the name with an `"output."` prefix. + + The optional `unlisted` parameter is a boolean to control if the output panel should be listed in the panel + switcher. + """ ... - def destroy_output_panel(self, name: str) -> None: + def find_output_panel(self, name: str) -> View | None: + """ + The `View` associated with the named output panel, or `None` if the output panel does not exist. + """ ... - def active_panel(self) -> Optional[str]: + def destroy_output_panel(self, name: str) -> None: + """ + Destroy the named output panel, hiding it if currently open. + """ ... - def panels(self) -> List[str]: + def active_panel(self) -> str | None: + """ + Returns the name of the currently open panel, or None if no panel is open. Will return built-in panel names + (e.g. `"console"`, `"find"`, etc.) in addition to output panels. + """ ... - def get_output_panel(self, name: str) -> 'Optional[View]': + def panels(self) -> List[str]: + """ + Returns a list of the names of all panels that have not been marked as unlisted. Includes certain built-in + panels in addition to output panels. + """ ... - def show_input_panel(self, caption: str, initial_text: str, on_done: Optional[Callable], - on_change: Optional[Callable], on_cancel: Optional[Callable]) -> 'View': + @deprecated("Use create_output_panel(...) instead") + def get_output_panel(self, name: str) -> View | None: ... - def show_quick_panel(self, - items: List[Any], - on_select: Callable, - flags: int = ..., - selected_index: int = ..., - on_highlight: Optional[Callable] = ..., - placeholder: Optional[str] = ...) -> None: + def show_input_panel( + self, + caption: str, + initial_text: str, + on_done: Callable[[str], None] | None, + on_change: Callable[[str], None] | None, + on_cancel: Callable[[], None] | None + ) -> View: + """ + Shows the input panel, to collect a line of input from the user. + + - `caption` - The label to put next to the input widget. + - `initial_text` - The initial text inside the input widget. + - `on_done` - Called with the final input when the user presses Enter. + - `on_change` - Called with the input when it's changed. + - `on_cancel` - Called when the user cancels input using Esc. + + Returns the `View` used for the input widget. + """ + ... + + def show_quick_panel( + self, + items: List[Any], + on_select: Callable[..., None], + flags: int = ..., + selected_index: int = ..., + on_highlight: Callable[..., None] = ..., + placeholder: str | None = ... + ) -> None: + """ + Show a quick panel to select an item in a list. on_select will be called once, with the index of the selected + item. If the quick panel was cancelled, `on_select` will be called with an argument of `-1`. + + - `items` - May be either a list of strings, a list of lists of strings where the first item is the trigger + and all subsequent strings are details shown below, or a `QuickPanelItem`. + - `on_select` - Called with the selected item's index when the quick panel is completed. If the panel was + cancelled this is called with `-1`. A second `Event` argument may be passed when the `WANT_EVENT` flag is + present. + - `flags` - Flags controlling behavior. + - `selected_index` - The initially selected item. `-1` for no selection. + - `on_highlight` - Called every time the highlighted item in the quick panel is changed. + - `placeholder` - Text displayed in the filter input field before any query is typed. + """ ... def is_sidebar_visible(self) -> bool: + """ + Whether the sidebar is visible. + """ ... - def set_sidebar_visible(self, flag: bool) -> None: + def set_sidebar_visible(self, flag: bool, animate: bool = ...) -> None: + """ + Hides or shows the sidebar. + """ ... def is_minimap_visible(self) -> bool: + """ + Whether the minimap is visible. + """ ... def set_minimap_visible(self, flag: bool) -> None: + """ + Hides or shows the minimap. + """ ... def is_status_bar_visible(self) -> bool: + """ + Whether the status bar is visible. + """ ... def set_status_bar_visible(self, flag: bool) -> None: + """ + Hides or shows the status bar. + """ ... def get_tabs_visible(self) -> bool: + """ + Whether the tabs are visible. + """ ... def set_tabs_visible(self, flag: bool) -> None: + """ + Hides or shows the tabs. + """ ... def is_menu_visible(self) -> bool: + """ + Whether the menu is visible. + """ ... def set_menu_visible(self, flag: bool) -> None: + """ + Hides or shows the menu. + """ ... def folders(self) -> List[str]: + """ + A list of the currently open folders in this `Window`. + """ + ... + + def project_file_name(self) -> str | None: + """ + The name of the currently opened project file, if any. + """ ... - def project_file_name(self) -> str: + def project_data(self) -> bool | str | int | float | List[Any] | Dict[str, Any] | None: + """ + The project data associated with the current window. The data is in the same format as the contents of a + `.sublime-project` file. + """ ... - def project_data(self) -> Optional[dict]: + def set_project_data(self, v: bool | str | int | float | List[Any] | Dict[str, Any] | None) -> None: + """ + Updates the project data associated with the current window. If the window is associated with a + `.sublime-project` file, the project file will be updated on disk, otherwise the window will store the data + internally. + """ ... - def set_project_data(self, v: Union[dict, None]) -> None: + def workspace_file_name(self) -> str | None: + """ + The name of the currently opened workspace file, if any. + """ ... def settings(self) -> Settings: + """ + The `Settings` object for this `Window`. Any changes to this settings object will be specific to this window. + """ + ... + + def template_settings(self): + """ + Per-window settings that are persisted in the session, and duplicated into new windows. + """ + ... + + def symbol_locations( + self, + sym: str, + source: int = ..., + type: int = ..., + kind_id: int = ..., + kind_letter: str = ... + ) -> List[SymbolLocation]: + """ + Find all locations where the symbol `sym` is located. + + - `sym` - The name of the symbol. + - `source` - Sources which should be searched for the symbol. + - `type` - The type of symbol to find. + - `kind_id` - The kind ID of the symbol. + - `kind_letter` - The letter representing the kind of the symbol. + + Returns the found symbol locations. + """ + ... + + @deprecated("Use symbol_locations() instead") + def lookup_symbol_in_index(self, sym: str) -> List[SymbolLocation]: + """ + All locations where the symbol is defined across files in the current project. + """ ... - # def template_settings(self): ... - def lookup_symbol_in_index(self, sym: str) -> List[str]: + @deprecated("Use symbol_locations() instead") + def lookup_symbol_in_open_files(self, sym: str) -> List[SymbolLocation]: + """ + All locations where the symbol is defined across open files. + """ ... - def lookup_symbol_in_open_files(self, sym: str) -> List[str]: + @deprecated("Use symbol_locations() instead") + def lookup_references_in_index(self, symbol: str) -> List[SymbolLocation]: + """ + All locations where the symbol is referenced across files in the current project. + """ ... - def extract_variables(self) -> dict: + @deprecated("Use symbol_locations() instead") + def lookup_references_in_open_files(self, symbol: str) -> List[SymbolLocation]: + """ + All locations where the symbol is referenced across open files. + """ + ... + + def extract_variables(self) -> Dict[str, str]: + """ + Get the `dict` of contextual keys of the window. + + May contain: + + * `"packages"` + * `"platform"` + * `"file"` + * `"file_path"` + * `"file_name"` + * `"file_base_name"` + * `"file_extension"` + * `"folder"` + * `"project"` + * `"project_path"` + * `"project_name"` + * `"project_base_name"` + * `"project_extension"` + + This `dict` is suitable for use with `expand_variables()`. + """ ... def status_message(self, msg: str) -> None: + """ + Show a message in the status bar. + """ ... class Edit: - edit_token = ... # type: Any + """ + A grouping of buffer modifications. + + `Edit` objects are passed to `TextCommand`s, and can not be created by the user. Using an invalid `Edit` object, or + an `Edit` object from a different `View`, will cause the functions that require them to fail. + """ + edit_token: int - def __init__(self, token: Any) -> None: + def __init__(self, token: int) -> None: ... class Region: - a = ... # type: int - b = ... # type: int - xpos = ... # type: int + """ + A singular selection region. This region has a order - `b` may be before or at `a`. - def __init__(self, a: int, b: Optional[int] = ..., xpos: int = ...) -> None: + Also commonly used to represent an area of the text buffer, where ordering and `xpos` are generally ignored. + """ + a: int + """The first end of the region.""" + b: int + """The second end of the region. In a selection this is the location of the caret. May be less than `a`.""" + xpos: float + """ + In a selection this is the target horizontal position of the region. This affects behavior when pressing the up or + down keys. Use `-1` if undefined. + """ + + def __init__(self, a: int, b: int | None = ..., xpos: float = ...) -> None: ... def __len__(self) -> int: + """The size of the region.""" ... def __eq__(self, rhs: object) -> bool: + """Whether the two regions are identical. Ignores `xpos`.""" ... def __lt__(self, rhs: object) -> bool: + """Whether this region starts before the rhs. The end of the region is used to resolve ties.""" + ... + + def to_tuple(self) -> Tuple[int, int]: + """ + Returns a tuple of this region (excluding xpos). + + Use this to uniquely identify a region in a set or similar. Regions + can't be used for that directly as they may be mutated. + """ ... def empty(self) -> bool: + """Whether the region is empty, ie. `a == b`.""" ... def begin(self) -> int: + """The smaller of `a` and `b`.""" ... def end(self) -> int: + """The larger of `a` and `b`.""" ... def size(self) -> int: + """Equivalent to `__len__`.""" ... - def contains(self, x: 'Union[Region, int]') -> bool: + def contains(self, x: Region | int) -> bool: ... - def cover(self, rhs: 'Region') -> 'Region': + def cover(self, rhs: Region) -> Region: + """A `Region` spanning both regions.""" ... - def intersection(self, rhs: 'Region') -> 'Region': + def intersection(self, rhs: Region) -> Region: + """A `Region` covered by both regions.""" ... - def intersects(self, rhs: 'Region') -> bool: + def intersects(self, rhs: Region) -> bool: + """Whether the provided region intersects this region.""" ... - def to_tuple(self) -> Tuple[int, int]: + +class HistoricPosition: + """ + Provides a snapshot of the row and column info for a `Point`, before changes were made to a `View`. This is + primarily useful for replaying changes to a document. + """ + pt: int + """The offset from the beginning of the `View`.""" + row: int + """The row the `pt` was in when the `HistoricPosition` was recorded.""" + col: int + """The column the `py` was in when the `HistoricPosition` was recorded, in Unicode characters.""" + col_utf16: int + """The value of `col`, but in UTF-16 code units.""" + col_utf8: int + """The value of `col`, but in UTF-8 code units.""" + + +class TextChange: + """ + Represents a change that occurred to the text of a `View`. This is primarily useful for replaying changes to a + document. + """ + a: HistoricPosition + """The beginning `HistoricPosition` of the region that was modified.""" + b: HistoricPosition + """The ending `HistoricPosition` of the region that was modified.""" + len_utf16: int + """The length of the old contents, in UTF-16 code units.""" + len_utf8: int + """The length of the old contents, in UTF-8 code units.""" + str: str + """A string of the new contents of the region specified by `a` and `b`.""" + + def __init__(self, pa: HistoricPosition, pb: HistoricPosition, len_utf16: int, len_utf8: int, s: str) -> None: ... class Selection(Reversible): - view_id = ... # type: Any + """ + Maintains a set of sorted non-overlapping Regions. A selection may be empty. - def __init__(self, id: Any) -> None: + This is primarily used to represent the textual selection. + """ + view_id: int + + def __init__(self, id: int) -> None: ... def __reversed__(self) -> Iterator[Region]: @@ -602,95 +1371,185 @@ class Selection(Reversible): ... def __len__(self) -> int: + """ + The number of regions in the selection. + """ ... def __getitem__(self, index: int) -> Region: + """ + The region at the given `index`. + """ ... def __delitem__(self, index: int) -> None: + """ + Delete the region at the given `index`. + """ ... - def __eq__(self, rhs: Any) -> bool: + def __eq__(self, rhs: Selection | None) -> bool: + """ + Whether the selections are identical. + """ ... - def __lt__(self, rhs: Any) -> bool: + def __lt__(self, rhs: Selection | None) -> bool: ... def __bool__(self) -> bool: + """ + The selection is `True` when not empty. + """ ... def is_valid(self) -> bool: + """ + Whether this selection is for a valid view. + """ ... def clear(self) -> None: + """ + Remove all regions from the selection. + """ ... - def add(self, x: Union[Region, int]) -> None: + def add(self, x: Region | int) -> None: + """ + Add a `Region` or point to the selection. It will be merged with the existing regions if intersecting. + """ ... - def add_all(self, regions: Iterator[Union[Region, int]]) -> None: + def add_all(self, regions: Iterable[Region | int]) -> None: + """ + Add all the regions from the given iterable. + """ ... def subtract(self, region: Region) -> None: + """ + Subtract a region from the selection, such that the whole region is no longer contained within the selection. + """ ... def contains(self, region: Region) -> bool: + """ + Whether the provided region is contained within the selection. + """ ... class Sheet: - sheet_id = ... # type: Any + """ + Represents a content container, i.e. a tab, within a window. Sheets may contain a `View`, or an image preview. + """ + sheet_id: int - def __init__(self, id: Any) -> None: + def __init__(self, id: int) -> None: ... def __eq__(self, other: object) -> bool: ... def id(self) -> int: + """A number that uniquely identifies this sheet.""" ... - def window(self) -> Optional[Window]: + def window(self) -> Window | None: + """The `Window` containing this sheet. May be `None` if the sheet has been closed.""" ... - def group(self) -> int: + def view(self) -> View | None: + """The `View` contained within the sheet if any.""" ... - def view(self) -> 'Optional[View]': + def file_name(self) -> str | None: + """The full name of the file associated with the sheet, or `None` if it doesn't exist on disk.""" ... def is_semi_transient(self) -> bool: + """Whether this sheet is semi-transient.""" ... def is_transient(self) -> bool: + """ + Whether this sheet is exclusively transient. + + Note that a sheet may be both open as a regular file and be transient. In this case `is_transient` will still + return `False`. + """ ... + def is_selected(self) -> bool: + """Whether this sheet is currently selected.""" + ... -class HtmlSheet(Sheet): - sheet_id = ... # type: Any + def group(self) -> int | None: + """The (layout) group that the sheet is contained within.""" + ... - def __init__(self, id: Any) -> None: + def close(self, on_close: Callable[[bool], None] = ...) -> None: + """Closes the sheet.""" ... + +class TextSheet(Sheet): + """ + Specialization for sheets containing editable text, ie. a `View`. + """ + def set_name(self, name: str) -> None: + """Set the name displayed in the tab. Only affects unsaved files.""" + ... + + +class ImageSheet(Sheet): + """ + Specialization for sheets containing an image. + """ + ... + + +class HtmlSheet(Sheet): + """ + Specialization for sheets containing HTML. + """ def set_name(self, name: str) -> None: + """Set the name displayed in the tab.""" ... def set_contents(self, contents: str) -> None: + """Set the HTML content of the sheet.""" ... class ContextStackFrame: - context_name = ... # type: str - source_file = ... # type: str - source_location = ... # type: Tuple[int, int] + """ + Represents a single stack frame in the syntax highlighting. + """ + context_name: str + """The name of the context.""" + source_file: str + """The name of the file the context is defined in.""" + source_location: Tuple[int, int] + """ + The location of the context inside the source file as a pair of row and column. Maybe be `(-1, -1)` if the location + is unclear, like in tmLanguage based syntaxes. + """ class View: - view_id = ... # type: Any - selection = ... # type: Any - settings_object = ... # type: Any + """ + Represents a view into a text `Buffer`. - def __init__(self, id: Any) -> None: + Note that multiple views may refer to the same `Buffer`, but they have their own unique selection and geometry. A + list of these may be gotten using `View.clones()` or `Buffer.views()`. + """ + view_id: int + selection: Selection + settings_object: Settings | None + + def __init__(self, id: int) -> None: ... def __len__(self) -> int: @@ -702,347 +1561,1083 @@ class View: def __bool__(self) -> bool: ... - def sheet(self) -> Sheet: + def id(self) -> int: + """ + A number that uniquely identifies this view. + """ ... - def syntax(self) -> Any: + def buffer_id(self) -> int: + """ + A number that uniquely identifies this view's `Buffer`. + """ ... - def element(self) -> Optional[str]: + def buffer(self) -> Buffer: + """ + The `Buffer` for which this is a view. + """ ... - def id(self) -> int: + def sheet_id(self) -> int: + """ + The ID of the `Sheet` for this `View`, or `0` if not part of any sheet. + """ ... - def buffer(self) -> "Optional[Buffer]": + def sheet(self) -> Sheet | None: + """ + The `Sheet` for this view, if displayed in a sheet. + """ ... - def buffer_id(self) -> int: + def element(self) -> str | None: + """ + Returns `None` for normal views that are part of a `Sheet`. For views that comprise part of the UI a string is + returned from the following list: + + * `"console:input"` - The console input. + * `"goto_anything:input"` - The input for the Goto Anything. + * `"command_palette:input"` - The input for the Command Palette. + * `"find:input"` - The input for the Find panel. + * `"incremental_find:input"` - The input for the Incremental Find panel. + * `"replace:input:find"` - The Find input for the Replace panel. + * `"replace:input:replace"` - The Replace input for the Replace panel. + * `"find_in_files:input:find"` - The Find input for the Find in Files panel. + * `"find_in_files:input:location"` - The Where input for the Find in Files panel. + * `"find_in_files:input:replace"` - The Replace input for the Find in Files panel. + * `"find_in_files:output"` - The output panel for Find in Files (buffer or output panel). + * `"input:input"` - The input for the Input panel. + * `"exec:output"` - The output for the exec command. + * `"output:output"` - A general output panel. + + The console output, indexer status output and license input controls are not accessible via the API. + """ ... def is_valid(self) -> bool: + """ + Check whether this view is still valid. Will return `False` for a closed view, for example. + """ ... def is_primary(self) -> bool: + """ + Whether view is the primary view into a `Buffer`. Will only be `False` if the user has opened multiple views + into a file. + """ ... - def window(self) -> Optional[Window]: + def window(self) -> Window | None: + """ + A reference to the window containing the view, if any. + """ ... - def file_name(self) -> Optional[str]: + def clones(self) -> List[View]: + """ + All the other views into the same `Buffer`. + """ ... - def close(self) -> None: + def file_name(self) -> str | None: + """ + The full name of the file associated with the sheet, or `None` if it doesn't exist on disk. + """ + ... + + def close(self, on_close: Callable[[bool], None] = ...) -> None: + """ + Closes the view. + """ ... def retarget(self, new_fname: str) -> None: + """ + Change the file path the buffer will save to. + """ ... def name(self) -> str: + """ + The name assigned to the buffer, if any. + """ ... def set_name(self, name: str) -> None: + """ + Assign a name to the buffer. Displayed as in the tab for unsaved files. + """ + ... + + def reset_reference_document(self) -> None: + """ + Clears the state of the incremental diff for the view. + """ + ... + + def set_reference_document(self, reference: str) -> None: + """ + Uses the string reference to calculate the initial diff for the incremental diff. + """ ... def is_loading(self) -> bool: + """ + Whether the buffer is still loading from disk, and not ready for use. + """ ... def is_dirty(self) -> bool: + """ + Whether there are any unsaved modifications to the buffer. + """ ... def is_read_only(self) -> bool: + """ + Whether the buffer may not be modified. + """ ... def set_read_only(self, read_only: bool) -> None: + """ + Set the read only property on the buffer. + """ ... def is_scratch(self) -> bool: + """ + Whether the buffer is a scratch buffer. See `set_scratch()`. + """ ... def set_scratch(self, scratch: bool) -> None: + """ + Sets the scratch property on the buffer. When a modified scratch buffer is closed, it will be closed without + prompting to save. Scratch buffers never report as being dirty. + """ ... def encoding(self) -> str: + """ + The encoding currently associated with the buffer. + """ ... def set_encoding(self, encoding_name: str) -> None: + """ + Applies a new encoding to the file. This will be used when the file is saved. + """ ... def line_endings(self) -> str: + """ + The encoding currently associated with the file. + """ ... def set_line_endings(self, line_ending_name: str) -> None: + """ + Sets the line endings that will be applied when next saving. + """ ... def size(self) -> int: + """ + The number of character in the file. + """ ... - # def begin_edit(self, edit_token, cmd, args: Optional[Any] = ...) -> Edit: ... - # def end_edit(self, edit: Edit) -> None: ... - def is_in_edit(self) -> bool: - ... + # def begin_edit(self, edit_token: int, cmd: str, args: Dict[str, Any] | None = ...) -> Edit: # undocumented + # ... + + # def end_edit(self, edit: Edit) -> None: # undocumented + # ... + + # def is_in_edit(self) -> bool: # undocumented + # ... def insert(self, edit: Edit, pt: int, text: str) -> None: + """ + Insert the given string into the buffer. + + - `edit` - An `Edit` object provided by a `TextCommand`. + - `point` - The text point in the view where to insert. + - `text` - The text to insert. + + Returns the actual number of characters inserted. This may differ from the provided text due to tab translation. + + Raises `ValueError` if the `Edit` object is in an invalid state, ie. outside of a `TextCommand`. + """ ... def erase(self, edit: Edit, r: Region) -> None: + """ + Erases the contents of the provided `Region` from the buffer. + """ ... def replace(self, edit: Edit, r: Region, text: str) -> None: + """ + Replaces the contents of the `Region` in the buffer with the provided string. + """ ... def change_count(self) -> int: + """ + The current change count. + + Each time the buffer is modified, the change count is incremented. The change count can be used to determine if + the buffer has changed since the last it was inspected. + """ + ... + + def change_id(self) -> Tuple[int, int, int]: + """ + Get a 3-element tuple that can be passed to `transform_region_from()` to obtain a region equivalent to a region + of the view in the past. This is primarily useful for plugins providing text modification that must operate in + an asynchronous fashion and must be able to handle the view contents changing between the request and response. + """ + ... + + def transform_region_from(self, r: Region, when: Tuple[int, int, int]) -> Region: + """ + Transforms a region from a previous point in time to an equivalent region in the current state of the `View`. + `when` must have been obtained from `change_id()` at the point in time the region is from. + """ ... - def run_command(self, cmd: str, args: Optional[Any] = ...) -> None: + def run_command(self, cmd: str, args: Dict[str, Any] | None = ...) -> None: + """ + Run the named `TextCommand` with the (optional) given `args`. + """ ... def sel(self) -> Selection: + """ + The views `Selection`. + """ ... - def substr(self, x: Union[Region, int]) -> str: + def substr(self, x: Region | int) -> str: + """ + The string at the point or within the `Region` provided. + """ ... - def find(self, pattern: str, start_pt: int, flags: int = ...) -> Optional[Region]: + def find(self, pattern: str, start_pt: int, flags: int = ...) -> Region: + """ + The first `Region` matching the provided pattern. + + - `pattern` - The regex or literal pattern to search by. + - `start_pt` - The point to start searching from. + - `flags` - Controls various behaviors of find. + """ ... - def find_all(self, pattern: str, flags: int = ..., fmt: Optional[Any] = ..., - extractions: Optional[Any] = ...) -> 'List[Region]': + def find_all( + self, + pattern: str, + flags: int = ..., + fmt: str | None = ..., + extractions: List[str] | None = ... + ) -> List[Region]: + """ + All (non-overlapping) regions matching the pattern. + + - `pattern` - The regex or literal pattern to search by. + - `flags` - Controls various behaviors of find. + - `fmt` - When not `None` all matches in the `extractions` list will be formatted with the provided format + string. + - `extractions` - An optionally provided list to place the contents of the find results into. + """ ... def settings(self) -> Settings: + """ + The view's `Settings` object. Any changes to it will be private to this view. + """ + ... + + def meta_info(self, key: str, pt: int) -> bool | str | int | float | List[Any] | Dict[str, Any] | None: + """ + Look up the preference `key` for the scope at the provided point `pt` from all matching `.tmPreferences` files. + + Examples of keys are `TM_COMMENT_START` and `showInSymbolList`. + """ + ... + + def extract_tokens_with_scopes(self, r: Region) -> List[Tuple[Region, str]]: + """ + A list of pairs containing the `Region` and the scope of each token. + + - `region` - The region from which to extract tokens and scopes. + """ ... - # def meta_info(self, key, pt: int): ... def extract_scope(self, pt: int) -> Region: + """ + The extent of the syntax scope name assigned to the character at the given point `pt`, narrower syntax scope + names included. + """ + ... + + def expand_to_scope(self, pt: int, selector: str) -> Region | None: + """ + Expand by the provided scope selector from the `Point`. + + - `pt` - The point from which to expand. + - `selector` - The scope selector to match. + + Returns the matched `Region`, if any. + """ ... def scope_name(self, pt: int) -> str: + """ + The syntax scope name assigned to the character at the given point. + """ ... - def context_backtrace(self, pt: int) -> Union[List[ContextStackFrame], List[str]]: + def context_backtrace(self, pt: int) -> List[ContextStackFrame]: + """ + Get a backtrace of `ContextStackFrame`s at the provided point `pt`. + + Note this function is particularly slow. + """ ... def match_selector(self, pt: int, selector: str) -> bool: + """ + Whether the provided scope selector matches the point `pt`. + """ ... def score_selector(self, pt: int, selector: str) -> int: + """ + Equivalent to + ```python + sublime.score_selector(view.scope_name(pt), selector) + ``` + """ ... def find_by_selector(self, selector: str) -> List[Region]: + """ + Find all regions in the file matching the given selector. + """ ... - # def indented_region(self, pt: int): ... - # def indentation_level(self, pt: int): ... - def has_non_empty_selection_region(self) -> bool: + def style(self): + """ + The global style settings for the view. All colors are normalized to the six character hex form with a leading + hash, e.g. `#ff0000`. + """ + ... + + def style_for_scope(self, scope: str) -> Dict[str, Any]: + """ + Accepts a string scope name and returns a `dict` of style information including the keys: + + * `"foreground"` + * `"background"` (only if set and different from global background) + * `"bold"` + * `"italic"` + * `"glow"` + * `"underline"` + * `"stippled_underline"` + * `"squiggly_underline"` + * `"source_line"` + * `"source_column"` + * `"source_file"` + + The foreground and background colors are normalized to the six character hex form with a leading hash, e.g. + `#ff0000`. + """ + ... + + # def indented_region(self, pt: int) -> Region: # undocumented + # ... + + # def indentation_level(self, pt: int) -> int: # undocumented + # ... + + def has_non_empty_selection_region(self) -> bool: # undocumented ... def lines(self, r: Region) -> List[Region]: + """ + A list of lines (in sorted order) intersecting the provided `Region`. + """ ... def split_by_newlines(self, r: Region) -> List[Region]: + """ + Splits the region up such that each `Region` returned exists on exactly one line. + """ ... - def line(self, x: Union[Region, int]) -> Region: + def line(self, x: Region | int) -> Region: + """ + The line that contains the point or an expanded `Region` to the beginning/end of lines, excluding the newline + character. + """ ... - def full_line(self, x: Union[Region, int]) -> Region: + def full_line(self, x: Region | int) -> Region: + """ + The line that contains the point or an expanded `Region` to the beginning/end of lines, including the newline + character. + """ ... - def word(self, x: Union[Region, int]) -> Region: + def word(self, x: Region | int) -> Region: + """ + The word that contains the provided point. If a `Region` is provided it's beginning/end are expanded to word + boundaries. + """ ... def classify(self, pt: int) -> int: + """ + Classify the provided point. + """ ... - def find_by_class(self, pt: int, forward: bool, classes: int, separators: str = ...) -> int: - ... + def find_by_class( + self, + pt: int, + forward: bool, + classes: int, + separators: str = ..., + sub_word_separators: str = ... + ) -> int: + """ + Find the next location that matches the provided classification. + + - `pt` - The point to start searching from. + - `forward` - Whether to search forward or backwards. + - `classes` - The classification to search for. + - `separators` - The word separators to use when classifying. + - `sub_word_separators` - The sub-word separators to use when classifying. + """ + ... + + def expand_by_class( + self, + x: Region | int, + classes: int, + separators: str = ..., + sub_word_separators: str = ... + ) -> Region: + """ + Expand the provided point or `Region` to the left and right until each side lands on a location that matches the + provided classification. - def expand_by_class(self, x: Union[Region, int], classes: int, separators: str = ...) -> Region: + - `classes` - The classification to search by. + - `separators` - The word separators to use when classifying. + - `sub_word_separators` - The sub-word separators to use when classifying. + """ ... def rowcol(self, tp: int) -> Tuple[int, int]: + """ + Calculates the 0-based line and column numbers of the point. Column numbers are returned as number of Unicode + characters. + """ ... def rowcol_utf8(self, tp: int) -> Tuple[int, int]: + """ + Calculates the 0-based line and column numbers of the point. Column numbers are returned as UTF-8 code units. + """ ... def rowcol_utf16(self, tp: int) -> Tuple[int, int]: + """ + Calculates the 0-based line and column numbers of the point. Column numbers are returned as UTF-16 code units. + """ ... - def text_point(self, row: int, col: int, *, clamp_column: bool = False) -> int: + def text_point(self, row: int, col: int, *, clamp_column: bool = ...) -> int: + """ + Calculates the character offset of the given, 0-based, `row` and `col`. `col` is interpreted as the number of + Unicode characters to advance past the beginning of the row. + + - `clamp_column` - Whether `col` should be restricted to valid values for the given `row`. + """ ... - def text_point_utf8(self, row: int, col_utf8: int, *, clamp_column: bool = False) -> int: + def text_point_utf8(self, row: int, col_utf8: int, *, clamp_column: bool = ...) -> int: + """ + Calculates the character offset of the given, 0-based, `row` and `col`. `col` is interpreted as the number of + UTF-8 code units to advance past the beginning of the row. + + - `clamp_column` - Whether `col` should be restricted to valid values for the given `row`. + """ ... - def text_point_utf16(self, row: int, col_utf16: int, *, clamp_column: bool = False) -> int: + def text_point_utf16(self, row: int, col_utf16: int, *, clamp_column: bool = ...) -> int: + """ + Calculates the character offset of the given, 0-based, `row` and `col`. `col` is interpreted as the number of + UTF-16 code units to advance past the beginning of the row. + + - `clamp_column` - Whether `col` should be restricted to valid values for the given `row`. + """ ... def visible_region(self) -> Region: + """ + The currently visible area of the view. + """ ... - def show(self, x: Union[Selection, Region, int], show_surrounds: bool = True, keep_to_left: bool = False, - animate: bool = True) -> None: + def show( + self, + x: Region | Selection | int, + show_surrounds: bool = ..., + keep_to_left: bool = ..., + animate: bool = ... + ) -> None: + """ + Scroll the view to show the given location. + + - `location` - The location to scroll the view to. For a `Selection` only the first `Region` is shown. + - `show_surrounds` - Whether to show the surrounding context around the location. + - `keep_to_left` - Whether the view should be kept to the left, if horizontal scrolling is possible. + - `animate` - Whether the scrolling should be animated. + """ ... - def show_at_center(self, x: Union[Selection, Region, int], animate: bool = True) -> None: + def show_at_center(self, x: Region | int, animate: bool = ...) -> None: + """ + Scroll the view to center on the location. + + - `x` - Which point or `Region` to scroll to. + - `animate` - Whether the scrolling should be animated. + """ ... def viewport_position(self) -> Tuple[int, int]: + """ + The offset of the viewport in layout coordinates. + """ ... def set_viewport_position(self, xy: Tuple[int, int], animate: bool = ...) -> None: + """ + Scrolls the viewport to the given layout position. + """ ... def viewport_extent(self) -> Tuple[int, int]: + """ + The width and height of the viewport. + """ ... def layout_extent(self) -> Tuple[int, int]: + """ + The width and height of the layout. + """ ... def text_to_layout(self, tp: int) -> Tuple[int, int]: + """ + Convert a text point to a layout position. + """ + ... + + def text_to_window(self, tp: int) -> Tuple[int, int]: + """ + Convert a text point to a window position. + """ ... def layout_to_text(self, xy: Tuple[int, int]) -> int: + """ + Convert a layout position to a text point. + """ + ... + + def layout_to_window(self, xy: Tuple[int, int]) -> Tuple[int, int]: + """ + Convert a layout position to a window position. + """ ... def window_to_layout(self, xy: Tuple[int, int]) -> Tuple[int, int]: + """ + Convert a window position to a layout position. + """ ... def window_to_text(self, xy: Tuple[int, int]) -> int: + """ + Convert a window position to a text point. + """ ... def line_height(self) -> float: + """ + The light height used in the layout. + """ ... def em_width(self) -> float: + """ + The typical character width used in the layout. + """ ... def is_folded(self, sr: Region) -> bool: + """ + Whether the provided `Region` is folded. + """ ... - # def folded_regions(self): ... - def fold(self, x: Union[Region, List[Region]]) -> bool: + def folded_regions(self) -> List[Region]: + """ + The list of folded regions. + """ ... - def unfold(self, x: Union[Region, List[Region]]) -> List[Region]: + def fold(self, x: Region | List[Region]) -> bool: + """ + Fold the provided `Region`(s). + + Returns `False` if the regions were already folded. + """ ... - def add_regions(self, key: str, regions: List[Region], scope: str = ..., icon: str = ..., flags: int = ..., - annotations: List[str] = ..., annotation_color: str = ..., - on_navigate: Callable[[str], None] = ..., on_close: Callable[[], None] = ...) -> None: + def unfold(self, x: Region | List[Region]) -> List[Region]: + """ + Unfold all text in the provided `Region`(s). + + Returns the unfolded regions. + """ + ... + + def add_regions( + self, + key: str, + regions: List[Region], + scope: str = ..., + icon: str = ..., + flags: int = ..., + annotations: List[str] = ..., + annotation_color: str = ..., + on_navigate: Callable[[str], None] = ..., + on_close: Callable[[], None] = ... + ) -> None: + """ + Adds visual indicators to regions of text in the view. Indicators include icons in the gutter, underlines under + the text, borders around the text and annotations. Annotations are drawn aligned to the right-hand edge of the + view and may contain HTML markup. + + - `key` - An identifier for the collection of regions. If a set of regions already exists for this key they will + be overridden. + - `regions` - The list of regions to add. These should not overlap. + - `scope` - An optional string used to source a color to draw the regions in. The scope is matched against the + color scheme. Examples include: `"invalid"` and `"string"`. + See [Scope Naming](https://www.sublimetext.com/docs/scope_naming.html) for a list of common scopes. If the + scope is empty, the regions won't be drawn. Also supports the following pseudo-scopes, to allow picking the + closest color from the user‘s color scheme: + - `"region.redish"` + - `"region.orangish"` + - `"region.yellowish"` + - `"region.greenish"` + - `"region.cyanish"` + - `"region.bluish"` + - `"region.purplish"` + - `"region.pinkish"` + - `icon` - An optional string specifying an icon to draw in the gutter next to each region. The icon will be + tinted using the color associated with the `scope`. Standard icon names are `"dot"`, `"circle"` and + `"bookmark"`. The icon may also be a full package-relative path, such as + `"Packages/Theme - Default/dot.png"`. + - `flags` - Flags specifying how the region should be drawn, among other behavior. + - `annotations` - An optional collection of strings containing HTML documents to display along the right-hand + edge of the view. There should be the same number of annotations as regions. See minihtml for supported + HTML. + - `annotation_color` - An optional string of the CSS color to use when drawing the left border of the annotation. + See [minihtml Reference: Colors](https://www.sublimetext.com/docs/minihtml.html#colors) for supported color + formats. + - `on_navigate` - Called when a link in an annotation is clicked. Will be passed the `href` of the link. + - `on_close` - Called when the annotations are closed. + """ ... def get_regions(self, key: str) -> List[Region]: + """ + The regions associated with the given `key`, if any. + """ ... def erase_regions(self, key: str) -> None: + """ + Remove the regions associated with the given `key`. + """ ... - # def add_phantom(self, key: str, region: Region, content: str, layout, on_navigate: Optional[Any] = ...): ... - # def erase_phantoms(self, key: str) -> None: ... - # def erase_phantom_by_id(self, pid) -> None: ... - # def query_phantom(self, pid): ... - # def query_phantoms(self, pids): ... - def assign_syntax(self, syntax_file: str) -> None: + # def add_phantom( + # self, key: str, region: Region, content: str, layout: int, on_navigate: Callable[[str], None] | None = ... + # ) -> int: # undocumented + # ... + + # def erase_phantoms(self, key: str) -> None: # undocumented + # ... + + # def erase_phantom_by_id(self, pid: int) -> None: # undocumented + # ... + + # def query_phantom(self, pid: int) -> List[Region]: # undocumented + # ... + + # def query_phantoms(self, pids: List[int]) -> List[Region]: # undocumented + # ... + + def assign_syntax(self, syntax: str | Syntax) -> None: + """ + Changes the syntax used by the view. `syntax` may be a packages path to a syntax file, a `scope:` specifier + string, or a `Syntax` object. + """ ... + @deprecated("Use assign_syntax(...) instead") def set_syntax_file(self, syntax_file: str) -> None: ... + def syntax(self) -> Any: + """ + The syntax assigned to the buffer. + """ + ... + + @deprecated("Use symbol_regions() instead") def symbols(self) -> List[Tuple[Region, str]]: ... - # def get_symbols(self): ... - # def indexed_symbols(self): ... + @deprecated("Use symbol_regions() instead") + def get_symbols(self) -> List[Tuple[Region, str]]: + ... + + @deprecated("Use indexed_symbol_regions() instead") + def indexed_symbols(self) -> List[Tuple[Region, str]]: + ... + + @deprecated("Use indexed_symbol_regions() instead") + def indexed_references(self) -> List[Tuple[Region, str]]: + ... + + def symbol_regions(self) -> List[SymbolRegion]: + """ + Info about symbols that are part of the view's symbol list. + """ + ... + + def indexed_symbol_regions(self, type: int = ...) -> List[SymbolRegion]: + """ + Info about symbols that are indexed. + + - `type` - The type of symbol to return. + """ + ... + def set_status(self, key: str, value: str) -> None: + """ + Add the status `key` to the view. The `value` will be displayed in the status bar, in a comma separated list of + all status values, ordered by key. Setting the `value` to `""` will clear the status. + """ ... def get_status(self, key: str) -> str: + """ + The previous assigned value associated with the given `key`, if any. + """ ... def erase_status(self, key: str) -> None: + """ + Clear the status associated with the provided `key`. + """ + ... + + def extract_completions(self, prefix: str, tp: int = ...) -> List[str]: + """ + Get a list of word-completions based on the contents of the view. + + - `prefix` - The prefix to filter words by. + - `tp` - The point by which to weigh words. Closer words are preferred. + """ ... - # def extract_completions(self, prefix: str, tp: int = ...): ... - # def find_all_results(self): ... - # def find_all_results_with_text(self): ... - def command_history(self, delta: int, modifying_only: bool = ...) -> 'Tuple[str, dict, int]': + # def find_all_results(self) -> List[Tuple[str, int, int]]: # undocumented + # ... + + # def find_all_results_with_text(self) -> List[Tuple[str, int, int]]: # undocumented + # ... + + def command_history(self, delta: int, modifying_only: bool = ...) -> Tuple[Optional[str], Optional[dict], int]: + """ + Get info on previous run commands stored in the undo/redo stack. + + - `delta` - The offset into the undo/redo stack. Positive values indicate to look in the redo stack for commands. + - `modifying_only` - Whether only commands that modify the text buffer are considered. + + Returns the command name, command arguments and repeat count for the history entry. If the undo/redo history + doesn't extend far enough, then `(None, None, 0)` will be returned. + """ ... def overwrite_status(self) -> bool: + """ + The overwrite status, which the user normally toggles via the insert key. + """ ... def set_overwrite_status(self, value: bool) -> None: + """ + Set the overwrite status. + """ ... - def show_popup_menu(self, items: List[str], on_select: 'Callable', flags: int = ...) -> None: + def show_popup_menu(self, items: List[str], on_select: Callable[[int], None], flags: int = ...) -> None: + """ + Show a popup menu at the caret, for selecting an item in a list. + + - `items` - The list of entries to show in the list. + - `on_select` - Called once with the index of the selected item. If the popup was cancelled `-1` is passed + instead. + - `flags` - must be `0`, currently unused. + """ ... - def show_popup(self, - content: str, - flags: int = ..., - location: int = ..., - max_width: int = ..., - max_height: int = ..., - on_navigate: Optional[Any] = ..., - on_hide: Optional[Any] = ...) -> None: + def show_popup( + self, + content: str, + flags: int = ..., + location: int = ..., + max_width: int = ..., + max_height: int = ..., + on_navigate: Callable[[str], None] | None = ..., + on_hide: Callable[[], None] | None = ... + ) -> None: + """ + Show a popup displaying HTML content. + + - `content` - The HTML content to display. + - `flags` - Flags controlling popup behavior. + - `location` - The point at which to display the popup. If `-1` the popup is shown at the current postion of the + caret. + - `max_width` - The maximum width of the popup. + - `max_height` - The maximum height of the popup. + - `on_navigate` - Called when a link is clicked in the popup. Passed the value of the `href` attribute of the + clicked link. + - `on_hide` - Called when the popup is hidden. + """ ... def update_popup(self, content: str) -> None: + """ + Update the content of the currently visible popup. + """ ... def is_popup_visible(self) -> bool: + """ + Whether a popup is currently shown. + """ ... def hide_popup(self) -> None: + """ + Hide the current popup. + """ ... def is_auto_complete_visible(self) -> bool: + """ + Whether the auto-complete menu is currently visible. + """ ... - def change_id(self) -> Any: # opaque handle object + def preserve_auto_complete_on_focus_lost(self): + """ + Sets the auto complete popup state to be preserved the next time the `View` loses focus. When the `View` regains + focus, the auto complete window will be re-shown, with the previously selected entry pre-selected. + """ ... - def transform_region_from(self, region: Region, change_id: Any) -> Region: + def export_to_html( + self, + regions=None, + minihtml: bool = ..., + enclosing_tags: bool = ..., + font_size: bool = ..., + font_family: bool = ... + ) -> str: + """ + Generates an HTML string of the current view contents, including styling for syntax highlighting. + + - `regions` - The region(s) to export. By default the whole view is exported. + - `minihtml` - Whether the exported HTML should be compatible with minihtml. + - `enclosing_tags` - Whether a `
` with base-styling is added. Note that without this no background color is + set. + - `font_size` - Whether to include the font size in the top level styling. Only applies when `enclosing_tags` is + `True`. + - `font_family` - Whether to include the font family in the top level styling. Only applies when `enclosing_tags` + is `True`. + """ ... - def style_for_scope(self, scope: str) -> Dict[str, Any]: + def clear_undo_stack(self) -> None: + """ + Clear the undo/redo stack. + """ ... class Buffer: - buffer_id = ... # type: int + """ + Represents a text buffer. Multiple `View` objects may share the same buffer. + """ + buffer_id: int def __init__(self, id: int) -> None: ... - def views(self) -> Optional[List[View]]: + def __eq__(self, other: object) -> bool: + ... + + def id(self) -> int: + """ + Returns a number that uniquely identifies this buffer. + """ + ... + + def file_name(self) -> str | None: + """ + The full name file the file associated with the buffer, or `None` if it doesn't exist on disk. + """ ... - def primary_view(self) -> Optional[View]: + def views(self) -> List[View]: + """ + Returns a list of all views that are associated with this buffer. + """ + ... + + def primary_view(self) -> View: + """ + The primary view associated with this buffer. + """ + ... + + + +class Settings: + """ + A `dict` like object that a settings hierarchy. + """ + settings_id: int + + def __init__(self, id: int) -> None: + ... + + def get( + self, + key: str, + default: bool | str | int | float | List[Any] | Dict[str, Any] | None = ... + ) -> Any: + """ + Returns the named setting. + """ + ... + + def has(self, key: str) -> bool: + """ + Returns whether the provided `key` is set. + """ + ... + + def set(self, key: str, value: bool | str | int | float | List[Any] | Dict[str, Any] | None) -> None: + """ + Set the named `key` to the provided `value`. + """ + ... + + def erase(self, key: str) -> None: + """ + Deletes the provided `key` from the setting. Note that a parent setting may also provide this key, thus deleting + may not entirely remove a key. + """ + ... + + def add_on_change(self, tag: str, callback: Callable[[], None]) -> None: + """ + Register a callback to be run whenever a setting is changed. + + - `tag` - A string associated with the callback. For use with `clear_on_change`. + - `callback` - A callable object to be run when a setting is changed. + """ + ... + + def clear_on_change(self, tag: str) -> None: + """ + Remove all callbacks associated with the provided `tag`. See `add_on_change`. + """ ... class Phantom: - region = ... # type: Region - content = ... # type: Any - layout = ... # type: Any - on_navigate = ... # type: Any - id = ... # type: Any + """ + Represents an minihtml-based decoration to display non-editable content interspersed in a `View`. Used with + `PhantomSet` to actually add the phantoms to the `View`. Once a `Phantom` has been constructed and added to the + `View`, changes to the attributes will have no effect. + """ + region: Region + """The `Region` associated with the phantom. The phantom is displayed at the start of the `Region`.""" + content: str + """The HTML content of the phantom.""" + layout: int + """How the phantom should be placed relative to the `region`.""" + on_navigate: Callable[[str], None] | None + """Called when a link in the HTML is clicked. The value of the `href` attribute is passed.""" - def __init__(self, region: Region, content: str, layout: int, on_navigate: Optional[Any] = ...) -> None: + def __init__( + self, + region: Region, + content: str, + layout: int, + on_navigate: Callable[[str], None] | None = ... + ) -> None: ... - def __eq__(self, rhs: object) -> bool: + def __eq__(self, rhs: 'Phantom') -> bool: + ... + + def to_tuple(self) -> Tuple[Tuple[int, int], str, int, Optional[Callable[[str], None]]]: + """ + Returns a tuple of this phantom containing the region, content, layout + and callback. + + Use this to uniquely identify a phantom in a set or similar. Phantoms + can't be used for that directly as they are mutable. + """ ... class PhantomSet: - view = ... # type: View - key = ... # type: Any - phantoms = ... # type: Any + """ + A collection that manages `Phantom` objects and the process of adding them, updating them and removing them from a + `View`. + """ + view: View + """The `View` the phantom set is attached to.""" + key: str + """A string used to group the phantoms together.""" + phantoms: List[Phantom] def __init__(self, view: View, key: str = ...) -> None: ... @@ -1050,57 +2645,281 @@ class PhantomSet: def __del__(self) -> None: ... - def update(self, new_phantoms: Sequence[Phantom]) -> None: + def update(self, new_phantoms: Iterable[Phantom]) -> None: + """ + Update the set of phantoms. If the `Phantom.region` of existing phantoms have changed they will be moved; new + phantoms are added and ones not present are removed. + """ ... -class HistoricPosition: - pt = ... # type: int - row = ... # type: int - col = ... # type: int - col_utf16 = ... # type: int - col_utf8 = ... # type: int +class Html: + """ + Used to indicate that a string is formatted as HTML. + """ + data: str + def __init__( + self, + data: str, + ) -> None: + ... -class TextChange: - a = ... # type: HistoricPosition - b = ... # type: HistoricPosition - str = ... # type: str - len_utf8 = ... # type: int - len_utf16 = ... # type: int + +class CompletionList: + """ + Represents a list of completions, some of which may be in the process of being asynchronously fetched. + """ + target: Any + completions: List[str] | List[Tuple[str, str]] | List[CompletionItem] | None + flags: int + + def __init__( + self, + completions: List[str] | List[Tuple[str, str]] | List[CompletionItem] | None = ..., + flags: int = ... + ) -> None: + """ + - `completions` - If `None` is passed, the method `set_completions()` must be called before the completions will + be displayed to the user. + - `flags` - Flags controlling auto-complete behavior. + """ + ... + + def set_completions(self, completions: List[str] | List[Tuple[str, str]] | List[CompletionItem], flags: int = ...) -> None: + """ + Sets the list of completions, allowing the list to be displayed to the user. + """ + ... + + +class CompletionItem: + """ + Represents an available auto-completion item. + """ + trigger: str + """Text to match against the user's input.""" + annotation: str + """A hint to draw to the right-hand side of the trigger.""" + completion: str + """Text to insert if the completion is specified. If empty the `trigger` will be inserted instead.""" + completion_format: int + """The format of the completion.""" + kind: Tuple[int, str, str] + """The kind of the completion.""" + details: str + """ + An optional minihtml description of the completion, shown in the detail pane at the bottom of the auto complete + window. + """ + flags: int + + def __init__( + self, + trigger: str, + annotation: str = ..., + completion: str = ..., + completion_format: int = ..., + kind: Tuple[int, str, str] = ..., + details: str = ..., + flags: int = ... + ) -> None: + ... + + def __eq__(self, rhs: 'CompletionItem') -> bool: + ... + + @classmethod + def snippet_completion( + cls, + trigger: str, + snippet: str, + annotation: str = ..., + kind: Tuple[int, str, str] = ..., + details: str = ... + ) -> 'CompletionItem': + """ + Specialized constructor for snippet completions. The `completion_format` is always `COMPLETION_FORMAT_SNIPPET`. + """ + ... + + @classmethod + def command_completion( + cls, + trigger: str, + command: str, + args: Dict[str, Any] = ..., + annotation: str = ..., + kind: Tuple[int, str, str] = ..., + details: str = ... + ) -> 'CompletionItem': + """ + Specialized constructor for command completions. The `completion_format` is always `COMPLETION_FORMAT_COMMAND`. + """ + ... + + +def list_syntaxes() -> List[Syntax]: + """List all known syntaxes. + + Returns a list of `Syntax`. + """ + ... + + +def syntax_from_path(path: str) -> Syntax | None: + """Get the syntax for a specific path. + + Returns a Syntax or `None`. + """ + ... + + +def find_syntax_by_name(name: str) -> List[Syntax]: + """Find syntaxes with the specified name. + + Name must match exactly. Return a list of `Syntax`. + """ + ... + + +def find_syntax_by_scope(scope: str) -> List[Syntax]: + """Find syntaxes with the specified scope. + + Scope must match exactly. Return a list of `Syntax`. + """ + ... + + +def find_syntax_for_file(path: str, first_line: str = ...) -> Syntax | None: + """Find the syntax to use for a path. + + Uses the file extension, various application settings and optionally the + first line of the file to pick the right syntax for the file. + + Returns a `Syntax`. + """ + ... + + +class Syntax: + """ + Contains information about a syntax. + """ + path: str + """The packages path to the syntax file.""" + name: str + """The name of the syntax.""" + hidden: bool + """If the syntax is hidden from the user.""" + scope: str + """The base scope name of the syntax.""" + + def __init__(self, path: str, name: str, hidden: bool, scope: str) -> None: + ... + + def __eq__(self, other: object) -> bool: + ... class QuickPanelItem: + """ + Represents a row in the quick panel, shown via `Window.show_quick_panel()`. + """ + trigger: str + """Text to match against user's input.""" + details: str | List[str] | Tuple[str] + """A minihtml string or list of strings displayed below the trigger.""" + annotation: str + """Hint to draw to the right-hand side of the row.""" + kind: Tuple[int, str, str] + """The kind of the item.""" + def __init__( self, trigger: str, - details: Union[str, List[str]] = "", - annotation: str = "", - kind: Tuple[int, str, str] = KIND_AMBIGUOUS + details: str | Sequence[str] = ..., + annotation: str = ..., + kind: Tuple[int, str, str] = ... ) -> None: ... class ListInputItem: - text = ... # type: str - value = ... # type: Any - details = ... # type: Union[str, List[str], Tuple[str]] - annotation = ... # type: str - kind = ... # type: Tuple[int, str, str] + """ + Represents a row shown via `ListInputHandler`. + """ + text: str + """Text to match against the user's input.""" + value: Any + """A `Value` passed to the command if the row is selected.""" + details: str | List[str] | Tuple[str] + """A minihtml string or list of strings displayed below the trigger.""" + annotation: str + """Hint to draw to the right-hand side of the row.""" + kind: Tuple[int, str, str] + """The kind of the item.""" + def __init__( self, text: str, - value: Any, - details: Union[str, List[str]] = "", - annotation: str = "", - kind: Tuple[int, str, str] = KIND_AMBIGUOUS + value: bool | str | int | float | List[Any] | Dict[str, Any] | None, + details: str | Sequence[str] = ..., + annotation: str = ..., + kind: Tuple[int, str, str] = ... ) -> None: ... -class Html: +class SymbolRegion: + """ + Contains information about a `Region` of a `View` that contains a symbol. + """ + name: str + """The name of the symbol.""" + region: Region + """The location of the symbol within the `View`.""" + syntax: str + """The name of the syntax for the symbol.""" + type: int + """The type of the symbol""" + kind: Tuple[int, str, str] + """The kind of the symbol.""" + + def __init__(self, name: str, region: Region, syntax: str, type: int, kind: Tuple[int, str, str]) -> None: + ... + + +class SymbolLocation: + """ + Contains information about a file that contains a symbol. + """ + path: str + """The filesystem path to the file containing the symbol.""" + display_name: str + """The project-relative path to the file containing the symbol.""" + row: int + """The row of the file the symbol is contained on.""" + col: int + """The column of the row that the symbol is contained on.""" + syntax: str + """The name of the syntax for the symbol.""" + type: int + """The type of the symbol.""" + kind: Tuple[int, str, str] + """The kind of the symbol.""" + def __init__( self, - text: str, + path: str, + display_name: str, + row: int, + col: int, + syntax: str, + type: int, + kind: Tuple[int, str, str] ) -> None: ... + + def path_encoded_position(self) -> str: + ... diff --git a/stubs/sublime_plugin.pyi b/stubs/sublime_plugin.pyi index 1a7b2a4a1..50945641c 100644 --- a/stubs/sublime_plugin.pyi +++ b/stubs/sublime_plugin.pyi @@ -1,182 +1,865 @@ -# Stubs for sublime_plugin (Python 3.5) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. -from sublime import View, Window, Edit, Buffer -from typing import Any, Optional, Dict, List -assert Optional - -# api_ready = ... # type: bool -# application_command_classes = ... # type: Any -# window_command_classes = ... # type: Any -# text_command_classes = ... # type: Any -# view_event_listener_classes = ... # type: Any -view_event_listeners = ... # type: Dict[int, List[ViewEventListener]] -# all_command_classes = ... # type: Any -# all_callbacks = ... # type: Any -# profile = ... # type: Any - -# def unload_module(module): ... -# def unload_plugin(modulename): ... -# def reload_plugin(modulename): ... -# def create_application_commands(): ... -# def create_window_commands(window_id): ... -# def create_text_commands(view_id): ... -# def on_api_ready(): ... -# def is_view_event_listener_applicable(cls, view): ... -# def create_view_event_listeners(classes, view): ... -# def check_view_event_listeners(view): ... -# def attach_view(view): ... - -# check_all_view_event_listeners_scheduled = ... # type: bool - -# def check_all_view_event_listeners(): ... -# def detach_view(view): ... -# def event_listeners_for_view(view): ... -# def find_view_event_listener(view, cls): ... -# def on_new(view_id): ... -# def on_new_async(view_id): ... -# def on_clone(view_id): ... -# def on_clone_async(view_id): ... - -# class Summary: -# max = ... # type: float -# sum = ... # type: float -# count = ... # type: int -# def __init__(self) -> None: ... -# def record(self, x): ... - -# def run_callback(event, callback, expr): ... -# def run_view_listener_callback(view, name): ... -# def run_async_view_listener_callback(view, name): ... -# def on_load(view_id): ... -# def on_load_async(view_id): ... -# def on_pre_close(view_id): ... -# def on_close(view_id): ... -# def on_pre_save(view_id): ... -# def on_pre_save_async(view_id): ... -# def on_post_save(view_id): ... -# def on_post_save_async(view_id): ... -# def on_modified(view_id): ... -# def on_modified_async(view_id): ... -# def on_selection_modified(view_id): ... -# def on_selection_modified_async(view_id): ... -# def on_activated(view_id): ... -# def on_activated_async(view_id): ... -# def on_deactivated(view_id): ... -# def on_deactivated_async(view_id): ... -# def on_query_context(view_id, key, operator, operand, match_all): ... -# def normalise_completion(c): ... -# def on_query_completions(view_id, prefix, locations): ... -# def on_hover(view_id, point, hover_zone): ... -# def on_text_command(view_id, name, args): ... -# def on_window_command(window_id, name, args): ... -# def on_post_text_command(view_id, name, args): ... -# def on_post_window_command(window_id, name, args): ... +# Stubs for sublime_plugin.py (Python 3.3 API Environment) +from sublime import Buffer, CompletionItem, CompletionList, Edit, Html, ListInputItem, Settings, TextChange, View, Window +from typing import Any, Dict, List, Tuple + + +view_event_listeners: Dict[int, List[ViewEventListener]] # undocumented + + +class CommandInputHandler: + + def name(self) -> str: + """ + The command argument name this input handler is editing. Defaults to `foo_bar` for an input handler named + `FooBarInputHandler`. + """ + ... + + def placeholder(self) -> str: + """ + Placeholder text is shown in the text entry box before the user has entered anything. Empty by default. + """ + ... + + def initial_text(self) -> str: + """ + Initial text shown in the text entry box. Empty by default. + """ + ... + + def initial_selection(self) -> List[Tuple[int, int]]: + """ + A list of 2-element tuples, defining the initially selected parts of the initial text. + """ + ... + + def preview(self, text: str) -> str | Html: + """ + Called whenever the user changes the text in the entry box. The returned value (either plain text or HTML) will + be shown in the preview area of the Command Palette. + """ + ... + + def validate(self, text: str) -> bool: + """ + Called whenever the user presses enter in the text entry box. Return `False` to disallow the current value. + """ + ... + + def cancel(self) -> None: + """ + Called when the input handler is canceled, either by the user pressing backspace or escape. + """ + ... + + def confirm(self, text: str) -> None: + """ + Called when the input is accepted, after the user has pressed enter and the text has been validated. + """ + ... + + def next_input(self, args) -> CommandInputHandler | None: + """ + Return the next input after the user has completed this one. May return + :py:`None` to indicate no more input is required, or + `sublime_plugin.BackInputHandler()` to indicate that the input handler + should be popped off the stack instead. + """ + ... + + def want_event(self) -> bool: + """ + Whether the `validate()` and `confirm()` methods should received a second `Event` parameter. Returns `False` by + default. + """ + ... + + +class BackInputHandler(CommandInputHandler): + ... + + +class TextInputHandler(CommandInputHandler): + """ + TextInputHandlers can be used to accept textual input in the Command Palette. Return a subclass of this from + `Command.input()`. + + For an input handler to be shown to the user, the command returning the input handler MUST be made available in the + Command Palette by adding the command to a `Default.sublime-commands` file. + """ + def description(self, text: str) -> str: + """ + The text to show in the Command Palette when this input handler is not at the top of the input handler stack. + Defaults to the text the user entered. + """ + ... + + +class ListInputHandler(CommandInputHandler): + """ + ListInputHandlers can be used to accept a choice input from a list items in the Command Palette. Return a subclass + of this from `Command.input()`. + + For an input handler to be shown to the user, the command returning the input handler MUST be made available in the + Command Palette by adding the command to a `Default.sublime-commands` file. + """ + def list_items(self) -> List[str] | Tuple[List[str], int] | List[Tuple[str, Any]] | \ + Tuple[List[Tuple[str, Any]], int] | List[ListInputItem] | Tuple[List[ListInputItem], int]: + """ + This method should return the items to show in the list. + + The returned value may be a `list` of items, or a 2-element `tuple` containing a list of items, and an `int` + index of the item to pre-select. + + Each item in the list may be one of: + + * A string used for both the row text and the value passed to the command + * A 2-element tuple containing a string for the row text, and a `Value` to pass to the command + * A `sublime.ListInputItem` object + """ + ... + + def description(self, value, text: str) -> str: + """ + The text to show in the Command Palette when this input handler is not at the top of the input handler stack. + Defaults to the text of the list item the user selected. + """ + ... class Command: + def name(self) -> str: + """ + Return the name of the command. By default this is derived from the name of the class. + """ ... - # def is_enabled_(self, args): ... - def is_enabled(self) -> bool: + def is_enabled(self, **kwargs: Dict[str, Any]) -> bool: + """ + Return whether the command is able to be run at this time. Command arguments are passed as keyword arguments. + The default implementation simply always returns `True`. + """ ... - # def is_visible_(self, args): ... - def is_visible(self) -> bool: + def is_visible(self, **kwargs: Dict[str, Any]) -> bool: + """ + Return whether the command should be shown in the menu at this time. Command arguments are passed as keyword + arguments. The default implementation always returns `True`. + """ ... - # def is_checked_(self, args): ... - def is_checked(self) -> bool: + def is_checked(self, **kwargs: Dict[str, Any]) -> bool: + """ + Return whether a checkbox should be shown next to the menu item. Command arguments are passed as keyword + arguments. The `.sublime-menu` file must have the `"checkbox"` key set to `true` for this to be used. + """ ... - # def description_(self, args): ... - def description(self) -> str: + def description(self, **kwargs: Dict[str, Any]) -> str: + """ + Return a description of the command with the given arguments. Command arguments are passed as keyword arguments. + Used in the menu, if no caption is provided. Return `None` to get the default description. + """ ... - # def filter_args(self, args): ... def want_event(self) -> bool: + """ + Return whether to receive an `Event` argument when the command is triggered by a mouse action. The event + information allows commands to determine which portion of the view was clicked on. The default implementation + returns `False`. + """ + ... + + def input(self, args: Dict[str, Any]) -> CommandInputHandler | None: + """ + If this returns something other than `None`, the user will be prompted for an input before the command is run in + the Command Palette. + """ + ... + + def input_description(self) -> str: + """ + Allows a custom name to be show to the left of the cursor in the input box, instead of the default one generated + from the command name. + """ + ... + + def run(self, **kwargs: Dict[str, Any]) -> None: + """ + Called when the command is run. Command arguments are passed as keyword arguments. + """ ... class ApplicationCommand(Command): + """ + A `Command` instantiated just once. + """ ... class WindowCommand(Command): - window = ... # type: Window + """ + A `Command` instantiated once per window. The `Window` object may be retrieved via `self.window`. + """ + window: Window + """The `Window` this command is attached to.""" def __init__(self, window: Window) -> None: ... - # def run_(self, edit_token, args): ... - - # def run(self) -> None: (mypy issue #5876). - # ... - class TextCommand(Command): - view = ... # type: View + """ + A `Command` instantiated once per `View`. The `View` object may be retrieved + via `self.view `. + """ + view: View + """The `View` this command is attached to.""" def __init__(self, view: View) -> None: ... - # def run_(self, edit_token, args): ... - # def run(self, edit: Edit) -> None: (mypy issue #5876) - # ... + def run(self, edit: Edit, **kwargs: Dict[str, Any]) -> None: + """ + Called when the command is run. Command arguments are passed as keyword arguments. + """ + ... class EventListener: - ... + def on_init(self, views: List[View]) -> None: + """ + Called once with a list of views that were loaded before the EventListener was instantiated. + """ + ... -class TextChangeListener: + def on_exit(self) -> None: + """ + Called once after the API has shut down, immediately before the plugin_host process exits. + """ + ... - buffer = ... # type: Buffer + def on_new(self, view: View) -> None: + """ + Called when a new file is created. + """ + ... - @classmethod - def is_applicable(cls, buffer: Buffer) -> bool: + def on_new_async(self, view: View) -> None: + """ + Called when a new buffer is created. Runs in a separate thread, and does not block the application. + """ ... - def __init__(self) -> None: + def on_associate_buffer(self, buffer: Buffer) -> None: + """ + Called when a buffer is associated with a file. `buffer` will be a `Buffer` object. + """ ... - def attach(self, buffer: Buffer) -> None: + def on_associate_buffer_async(self, buffer: Buffer) -> None: + """ + Called when a buffer is associated with file. Runs in a separate thread, and does not block the application. + `buffer` will be a `Buffer` object. + """ ... - def detach(self) -> None: + def on_clone(self, view: View) -> None: + """ + Called when a view is cloned from an existing one. + """ ... - def is_attached(self) -> bool: + def on_clone_async(self, view: View) -> None: + """ + Called when a view is cloned from an existing one. Runs in a separate thread, and does not block the + application. + """ + ... + + def on_load(self, view: View) -> None: + """ + Called when the file is finished loading. + """ + ... + + def on_load_async(self, view: View) -> None: + """ + Called when the file is finished loading. Runs in a separate thread, and does not block the application. + """ + ... + + def on_reload(self, view: View) -> None: + """ + Called when the View is reloaded. + """ + ... + + def on_reload_async(self, view: View) -> None: + """ + Called when the View is reloaded. Runs in a separate thread, and does not block the application. + """ + ... + + def on_revert(self, view: View) -> None: + """ + Called when the View is reverted. + """ + ... + + def on_revert_async(self, view: View) -> None: + """ + Called when the View is reverted. Runs in a separate thread, and does not block the application. + """ + ... + + def on_pre_move(self, view: View) -> None: + """ + Called right before a view is moved between two windows, passed the `View` object. + """ + ... + + def on_post_move(self, view: View) -> None: + """ + Called right after a view is moved between two windows, passed the `View` object. + """ + ... + + def on_post_move_async(self, view: View) -> None: + """ + Called right after a view is moved between two windows, passed the `View` object. Runs in a separate thread, and + does not block the application. + """ + ... + + def on_pre_close(self, view: View) -> None: + """ + Called when a view is about to be closed. The view will still be in the window at this point. + """ + ... + + def on_close(self, view: View) -> None: + """ + Called when a view is closed (note, there may still be other views into the same buffer). + """ + ... + + def on_pre_save(self, view: View) -> None: + """ + Called just before a view is saved. + """ + ... + + def on_pre_save_async(self, view: View) -> None: + """ + Called just before a view is saved. Runs in a separate thread, and does not block the application. + """ + ... + + def on_post_save(self, view: View) -> None: + """ + Called after a view has been saved. + """ + ... + + def on_post_save_async(self, view: View) -> None: + """ + Called after a view has been saved. Runs in a separate thread, and does not block the application. + """ + ... + + def on_modified(self, view: View) -> None: + """ + Called after changes have been made to a view. + """ + ... + + def on_modified_async(self, view: View) -> None: + """ + Called after changes have been made to a view. Runs in a separate thread, and does not block the application. + """ + ... + + def on_selection_modified(self, view: View) -> None: + """ + Called after the selection has been modified in a view. + """ + ... + + def on_selection_modified_async(self, view: View) -> None: + """ + Called after the selection has been modified in a view. Runs in a separate thread, and does not block the + application. + """ + ... + + def on_activated(self, view: View) -> None: + """ + Called when a view gains input focus. + """ + ... + + def on_activated_async(self, view: View) -> None: + """ + Called when a view gains input focus. Runs in a separate thread, and does not block the application. + """ + ... + + def on_deactivated(self, view: View) -> None: + """ + Called when a view loses input focus. + """ + ... + + def on_deactivated_async(self, view: View) -> None: + """ + Called when a view loses input focus. Runs in a separate thread, and does not block the application. + """ + ... + + def on_hover(self, view: View, point: int, hover_zone: int) -> None: + """ + Called when the user's mouse hovers over the view for a short period. + + - `view` - The view. + - `point` - The closest point in the view to the mouse location. The mouse may not actually be located adjacent + based on the value of `hover_zone`. + - `hover_zone` - Which element in Sublime Text the mouse has hovered over. + """ + ... + + def on_query_context(self, view: View, key: str, operator: int, operand: str, match_all: bool) -> bool | None: + """ + Called when determining to trigger a key binding with the given context key. If the plugin knows how to respond + to the context, it should return either `True` of `False`. If the context is unknown, it should return `None`. + + - `key` - The context key to query. This generally refers to specific state held by a plugin. + - `operator` - The operator to check against the operand; whether to check equality, inequality, etc. + - `operand` - The value against which to check using the `operator`. + - `match_all` - This should be used if the context relates to the selections: does every selection have to + match (`True`), or is at least one matching enough (`False`)? + """ + ... + + def on_query_completions( + self, + view: View, + prefix: str, + locations: List[int] + ) -> List[str] | Tuple[List[str], int] | List[Tuple[str, str]] | Tuple[List[Tuple[str, str]], int] | \ + List[CompletionItem] | Tuple[List[CompletionItem], int] | CompletionList | None: + """ + Called whenever completions are to be presented to the user. + + - `prefix` - The text already typed by the user. + - `locations` - The list of points being completed. Since this method is called for all completions no matter + the syntax, `self.view.match_selector(point, relevant_scope)` should be called to determine if the point is + relevant. + + Returns a list of completions in one of the valid formats or `None` if no completions are provided. + """ + ... + + def on_text_command(self, view: View, command_name: str, args: Dict[str, Any]) -> Tuple[str, Dict[str, Any]] | None: + """ + Called when a text command is issued. The listener may return a (command, arguments) tuple to rewrite the + command, or `None` to run the command unmodified. + """ + ... + + def on_window_command( + self, + window: Window, + command_name: str, + args: Dict[str, Any] + ) -> Tuple[str, Dict[str, Any]] | None: + """ + Called when a window command is issued. The listener may return a (command, arguments) tuple to rewrite the + command, or `None` to run the command unmodified. + """ + ... + + def on_post_text_command(self, view: View, command_name: str, args: Dict[str, Any]) -> None: + """ + Called after a text command has been executed. + """ + ... + + def on_post_window_command(self, window: Window, command_name: str, args: Dict[str, Any]) -> None: + """ + Called after a window command has been executed. + """ + ... + + def on_new_window(self, window: Window) -> None: + """ + Called when a window is created, passed the Window object. + """ + ... + + def on_new_window_async(self, window: Window) -> None: + """ + Called when a window is created, passed the Window object. Runs in a separate thread, and does not block the + application. + """ + ... + + def on_pre_close_window(self, window: Window) -> None: + """ + Called right before a window is closed, passed the Window object. + """ + ... + + def on_new_project(self, window: Window) -> None: + """ + Called right after a new project is created, passed the Window object. + """ + ... + + def on_new_project_async(self, window: Window) -> None: + """ + Called right after a new project is created, passed the Window object. Runs in a separate thread, and does not + block the application. + """ + ... + + def on_load_project(self, window: Window) -> None: + """ + Called right after a project is loaded, passed the Window object. + """ + ... + + def on_load_project_async(self, window: Window) -> None: + """ + Called right after a project is loaded, passed the Window object. Runs in a separate thread, and does not block + the application. + """ + ... + + def on_pre_save_project(self, window: Window) -> None: + """ + Called right before a project is saved, passed the Window object. + """ + ... + + def on_post_save_project(self, window: Window) -> None: + """ + Called right after a project is saved, passed the Window object. + """ + ... + + def on_post_save_project_async(self, window: Window) -> None: + """ + Called right after a project is saved, passed the Window object. Runs in a separate thread, and does not block + the application. + """ + ... + + def on_pre_close_project(self, window: Window) -> None: + """ + Called right before a project is closed, passed the Window object. + """ ... class ViewEventListener: + """ + A class that provides similar event handling to `EventListener`, but bound to a specific view. Provides class + method-based filtering to control what views objects are created for. + """ + view: View + @classmethod - def is_applicable(cls, settings: dict) -> bool: + def is_applicable(cls, settings: Settings) -> bool: + """ + Whether this listener should apply to a view with the given `Settings`. + """ ... @classmethod def applies_to_primary_view_only(cls) -> bool: + """ + Whether this listener should apply only to the primary view for a file or all of its clones as well. + """ ... - view = ... # type: View - def __init__(self, view: View) -> None: ... + def on_load(self) -> None: + """ + Called when the file is finished loading. + """ + ... -class CommandInputHandler: - ... + def on_load_async(self) -> None: + """ + Same as `on_load` but runs in a separate thread, not blocking the application. + """ + ... + def on_reload(self) -> None: + """ + Called when the file is reloaded. + """ + ... -class BackInputHandler(CommandInputHandler): - ... + def on_reload_async(self) -> None: + """ + Same as `on_reload` but runs in a separate thread, not blocking the application. + """ + ... + def on_revert(self) -> None: + """ + Called when the file is reverted. + """ + ... -class TextInputHandler(CommandInputHandler): - ... + def on_revert_async(self) -> None: + """ + Same as `on_revert` but runs in a separate thread, not blocking the application. + """ + ... + def on_pre_move(self) -> None: + """ + Called right before a view is moved between two windows. + """ + ... -class ListInputHandler(CommandInputHandler): - ... + def on_post_move(self) -> None: + """ + Called right after a view is moved between two windows. + """ + ... + + def on_post_move_async(self) -> None: + """ + Same as `on_post_move` but runs in a separate thread, not blocking the application. + """ + ... + + def on_pre_close(self) -> None: + """ + Called when a view is about to be closed. The view will still be in the window at this point. + """ + ... + + def on_close(self) -> None: + """ + Called when a view is closed (note, there may still be other views into the same buffer). + """ + ... + + def on_pre_save(self) -> None: + """ + Called just before a view is saved. + """ + ... + + def on_pre_save_async(self) -> None: + """ + Same as `on_pre_save` but runs in a separate thread, not blocking the application. + """ + ... + + def on_post_save(self) -> None: + """ + Called after a view has been saved. + """ + ... + + def on_post_save_async(self) -> None: + """ + Same as `on_post_save` but runs in a separate thread, not blocking the application. + """ + ... + + def on_modified(self) -> None: + """ + Called after changes have been made to the view. + """ + ... + + def on_modified_async(self) -> None: + """ + Same as `on_modified` but runs in a separate thread, not blocking the application. + """ + ... + + def on_selection_modified(self) -> None: + """ + Called after the selection has been modified in the view. + """ + ... + + def on_selection_modified_async(self) -> None: + """ + Called after the selection has been modified in the view. Runs in a separate thread, and does not block the + application. + """ + ... + + def on_activated(self) -> None: + """ + Called when a view gains input focus. + """ + ... + + def on_activated_async(self) -> None: + """ + Called when the view gains input focus. Runs in a separate thread, and does not block the application. + """ + ... + + def on_deactivated(self) -> None: + """ + Called when the view loses input focus. + """ + ... + + def on_deactivated_async(self) -> None: + """ + Called when the view loses input focus. Runs in a separate thread, and does not block the application. + """ + ... + + def on_hover(self, point: int, hover_zone: int) -> None: + """ + Called when the user's mouse hovers over the view for a short period. + + - `point` - The closest point in the view to the mouse location. The mouse may not actually be located adjacent + based on the value of `hover_zone`. + - `hover_zone` - Which element in Sublime Text the mouse has hovered over. + """ + ... + + def on_query_context(self, key: str, operator: int, operand: str, match_all: bool) -> bool | None: + """ + Called when determining to trigger a key binding with the given context key. If the plugin knows how to respond + to the context, it should return either `True` of `False`. If the context is unknown, it should return `None`. + + - `key` - The context key to query. This generally refers to specific state held by a plugin. + - `operator` - The operator to check against the operand; whether to check equality, inequality, etc. + - `operand` - The value against which to check using the `operator`. + - `match_all` - This should be used if the context relates to the selections: does every selection have to match + (`True`), or is at least one matching enough (`False`)? + """ + ... + + def on_query_completions( + self, + prefix: str, + locations: List[int] + ) -> List[str] | Tuple[List[str], int] | List[Tuple[str, str]] | Tuple[List[Tuple[str, str]], int] | \ + List[CompletionItem] | Tuple[List[CompletionItem], int] | CompletionList | None: + """ + Called whenever completions are to be presented to the user. + + - `prefix` - The text already typed by the user. + - `locations` - The list of points being completed. Since this method is called for all completions no matter + the syntax, `self.view.match_selector(point, relevant_scope)` should be called to determine if the point is + relevant. + + Returns a list of completions in one of the valid formats or `None` if no completions are provided. + """ + ... + + def on_text_command(self, command_name: str, args: Dict[str, Any]) -> Tuple[str, Dict[str, Any]] | None: + """ + Called when a text command is issued. The listener may return a `(command, arguments)` tuple to rewrite the + command, or `None` to run the command unmodified. + """ + ... + + def on_post_text_command(self, command_name: str, args: Dict[str, Any]) -> None: + """ + Called after a text command has been executed. + """ + ... + + +class TextChangeListener: + """ + A class that provides event handling about text changes made to a specific `Buffer`. Is separate from + `ViewEventListener` since multiple views can share a single buffer. + """ + buffer: Buffer + + @classmethod + def is_applicable(cls, buffer: Buffer) -> bool: + """ + Whether this listener should apply to the provided buffer. + """ + ... + + def __init__(self) -> None: + ... + + def detach(self) -> None: + """ + Remove this listener from the buffer. + + Async callbacks may still be called after this, as they are queued separately. + + Raises `ValueError` if the listener is not attached. + """ + ... + + def attach(self, buffer: Buffer) -> None: + """ + Attach this listener to a buffer. + + Raises `ValueError` if the listener is already attached. + """ + ... + + def is_attached(self) -> bool: + """ + Whether the listener is receiving events from a buffer. May not be called from `__init__`. + """ + ... + + def on_text_changed(self, changes: List[TextChange]) -> None: + """ + Called once after changes has been made to a buffer, with detailed information about what has changed. + """ + ... + + def on_text_changed_async(self, changes: List[TextChange]) -> None: + """ + Same as `on_text_changed` but runs in a separate thread, not blocking the application. + """ + ... + + def on_revert(self) -> None: + """ + Called when the buffer is reverted. + + A revert does not trigger text changes. If the contents of the buffer are required here use `View.substr`. + """ + ... + + def on_revert_async(self) -> None: + """ + Same as `on_revert` but runs in a separate thread, not blocking the application. + """ + ... + + def on_reload(self) -> None: + """ + Called when the buffer is reloaded. + + A reload does not trigger text changes. If the contents of the buffer are required here use `View.substr`. + """ + ... + + def on_reload_async(self) -> None: + """ + Same as `on_reload` but runs in a separate thread, not blocking the application. + """ + ... diff --git a/tests/test_types.py b/tests/test_types.py index a66b6a18f..5b1806cfd 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,4 +1,5 @@ from LSP.plugin.core.types import diff +from LSP.plugin.core.types import basescope2languageid from LSP.plugin.core.types import DocumentSelector from LSP.plugin.core.typing import List from unittest.mock import MagicMock @@ -145,3 +146,111 @@ def test_pattern_negated_character_range(self) -> None: self.assertFalse(selector.matches(self._make_html_view("example.7"))) self.assertFalse(selector.matches(self._make_html_view("example.8"))) self.assertFalse(selector.matches(self._make_html_view("example.9"))) + + def test_base_scope_to_language_id_mappings(self) -> None: + scope_test_map = { + "source.js.vite": "javascript", + "source.c++": "cpp", + "source.coffee.gulpfile": "coffeescript", + "source.cs": "csharp", + "source.css.tailwind": "css", + "source.dosbatch": "bat", + "source.fixedform-fortran": "fortran", + "source.groovy.gradle": "groovy", + "source.groovy.jenkins": "groovy", + "source.js": "javascript", + "source.js.eslint": "javascript", + "source.js.gruntfile": "javascript", + "source.js.gulpfile": "javascript", + "source.js.postcss": "javascript", + "source.js.puglint": "javascript", + "source.js.react": "javascriptreact", + "source.js.stylelint": "javascript", + "source.js.unittest": "javascript", + "source.js.webpack": "javascript", + "source.json-tmlanguage": "jsonc", + "source.json.babel": "json", + "source.json.bower": "json", + "source.json.composer": "json", + "source.json.eslint": "json", + "source.json.npm": "json", + "source.json.postcss": "json", + "source.json.puglint": "json", + "source.json.settings": "json", + "source.json.stylelint": "json", + "source.json.sublime": "jsonc", + "source.json.sublime.build": "jsonc", + "source.json.sublime.color-scheme": "jsonc", + "source.json.sublime.commands": "jsonc", + "source.json.sublime.completions": "jsonc", + "source.json.sublime.keymap": "jsonc", + "source.json.sublime.macro": "jsonc", + "source.json.sublime.menu": "jsonc", + "source.json.sublime.mousemap": "jsonc", + "source.json.sublime.project": "jsonc", + "source.json.sublime.settings": "jsonc", + "source.json.sublime.theme": "jsonc", + "source.json.tern": "json", + "source.jsx": "javascriptreact", + "source.jsx.unittest": "javascriptreact", + "source.Kotlin": "kotlin", + "source.modern-fortran": "fortran", + "source.objc": "objective-c", + "source.objc++": "objective-cpp", + "source.shader": "shaderlab", + "source.shell.bash": "shellscript", + "source.shell.docker": "shellscript", + "source.shell.eslint": "shellscript", + "source.shell.npm": "shellscript", + "source.shell.ruby": "shellscript", + "source.shell.stylelint": "shellscript", + "source.ts": "typescript", + "source.ts.react": "typescriptreact", + "source.ts.unittest": "typescript", + "source.tsx": "typescriptreact", + "source.tsx.unittest": "typescriptreact", + "source.unity.unity_shader": "shaderlab", + "source.viml.vimrc": "viml", + "source.yaml-tmlanguage": "yaml", + "source.yaml.circleci": "yaml", + "source.yaml.docker": "yaml", + "source.yaml.eslint": "yaml", + "source.yaml.lock": "yaml", + "source.yaml.procfile": "yaml", + "source.yaml.stylelint": "yaml", + "source.yaml.sublime.syntax": "yaml", + "source.yaml.yarn": "yaml", + "text.advanced_csv": "csv", + "text.django": "html", + "text.html.basic": "html", + "text.html.elixir": "html", + "text.html.markdown.academicmarkdown": "markdown", + "text.html.markdown.license": "markdown", + "text.html.markdown.rmarkdown": "r", + "text.html.ngx": "html", + "text.jinja": "html", + "text.plain": "plaintext", + "text.plain.buildpacks": "plaintext", + "text.plain.eslint": "plaintext", + "text.plain.fastq": "plaintext", + "text.plain.license": "plaintext", + "text.plain.lnk": "plaintext", + "text.plain.log": "plaintext", + "text.plain.nodejs": "plaintext", + "text.plain.pcb": "plaintext", + "text.plain.ps": "plaintext", + "text.plain.python": "plaintext", + "text.plain.readme": "plaintext", + "text.plain.ruby": "plaintext", + "text.plain.sketch": "plaintext", + "text.plain.visualstudio": "plaintext", + "text.plist": "xml", + "text.xml.plist": "xml", + "text.xml.plist.textmate.preferences": "xml", + "text.xml.sublime.snippet": "xml", + "text.xml.svg": "xml", + "text.xml.visualstudio": "xml", + } + + for base_scope, expected_language_id in scope_test_map.items(): + self.assertEqual(basescope2languageid(base_scope), expected_language_id) diff --git a/tests/test_url.py b/tests/test_url.py index 532278da5..9d782418a 100644 --- a/tests/test_url.py +++ b/tests/test_url.py @@ -70,4 +70,10 @@ def test_buffer_uri(self): view.file_name = unittest.mock.MagicMock(return_value=None) view.buffer_id = unittest.mock.MagicMock(return_value=42) uri = view_to_uri(view) - self.assertEqual(uri, "buffer://42") + self.assertEqual(uri, "buffer:42") + + def test_parse_uri(self): + scheme, _ = parse_uri("buffer:42") + self.assertEqual(scheme, "buffer") + scheme, _ = parse_uri("www.example.com/foo:bar") + self.assertEqual(scheme, "")