Skip to content

Commit

Permalink
Add support for inline completions
Browse files Browse the repository at this point in the history
  • Loading branch information
jwortmann committed Nov 11, 2024
1 parent 2f37a49 commit 57f6a30
Show file tree
Hide file tree
Showing 13 changed files with 350 additions and 10 deletions.
7 changes: 6 additions & 1 deletion ColorSchemes/Breakers.sublime-color-scheme
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{
"scope": "meta.semantic-token",
"background": "#00000001"
}
},
{
"scope": "meta.inline-completion",
"foreground": "color(var(grey3) alpha(0.6))",
"font_style": "italic"
},
]
}
7 changes: 6 additions & 1 deletion ColorSchemes/Celeste.sublime-color-scheme
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{
"scope": "meta.semantic-token",
"background": "#00000001"
}
},
{
"scope": "meta.inline-completion",
"foreground": "color(var(black) alpha(0.6))",
"font_style": "italic"
},
]
}
7 changes: 6 additions & 1 deletion ColorSchemes/Mariana.sublime-color-scheme
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{
"scope": "meta.semantic-token",
"background": "#00000001"
}
},
{
"scope": "meta.inline-completion",
"foreground": "color(var(white3) alpha(0.6))",
"font_style": "italic"
},
]
}
7 changes: 6 additions & 1 deletion ColorSchemes/Monokai.sublime-color-scheme
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{
"scope": "meta.semantic-token",
"background": "#00000001"
}
},
{
"scope": "meta.inline-completion",
"foreground": "color(var(white3) alpha(0.6))",
"font_style": "italic"
},
]
}
7 changes: 6 additions & 1 deletion ColorSchemes/Sixteen.sublime-color-scheme
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{
"scope": "meta.semantic-token",
"background": "#00000001"
}
},
{
"scope": "meta.inline-completion",
"foreground": "color(var(grey5) alpha(0.6))",
"font_style": "italic"
},
]
}
16 changes: 11 additions & 5 deletions Default.sublime-keymap
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@
// "args": {"overlay": "command_palette", "text": "LSP: "}
// },
// Insert/Replace Completions
// {
// "keys": ["UNBOUND"],
// "command": "lsp_commit_completion_with_opposite_insert_mode",
// "context": [
// {"key": "lsp.session_with_capability", "operand": "completionProvider"},
// {"key": "auto_complete_visible"}
// ]
// },
// Insert Inline Completion
{
"keys": ["alt+enter"],
"command": "lsp_commit_completion_with_opposite_insert_mode",
"context": [
{"key": "lsp.session_with_capability", "operand": "completionProvider"},
{"key": "auto_complete_visible"}
]
"command": "lsp_commit_inline_completion",
"context": [{"key": "lsp.inline_completion_visible"}]
},
// Save all open files that have a language server attached with lsp_save
// {
Expand Down
4 changes: 4 additions & 0 deletions boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
from .plugin.hover import LspToggleHoverPopupsCommand
from .plugin.inlay_hint import LspInlayHintClickCommand
from .plugin.inlay_hint import LspToggleInlayHintsCommand
from .plugin.inline_completion import LspCommitInlineCompletionCommand
from .plugin.inline_completion import LspInlineCompletionCommand
from .plugin.panels import LspClearLogPanelCommand
from .plugin.panels import LspClearPanelCommand
from .plugin.panels import LspShowDiagnosticsPanelCommand
Expand Down Expand Up @@ -99,6 +101,7 @@
"LspCollapseTreeItemCommand",
"LspColorPresentationCommand",
"LspCommitCompletionWithOppositeInsertMode",
"LspCommitInlineCompletionCommand",
"LspCopyToClipboardFromBase64Command",
"LspDisableLanguageServerGloballyCommand",
"LspDisableLanguageServerInProjectCommand",
Expand All @@ -120,6 +123,7 @@
"LspHierarchyToggleCommand",
"LspHoverCommand",
"LspInlayHintClickCommand",
"LspInlineCompletionCommand",
"LspNextDiagnosticCommand",
"LspOnDoubleClickCommand",
"LspOpenLinkCommand",
Expand Down
6 changes: 6 additions & 0 deletions docs/src/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,9 @@ The color scheme rule only works if the "background" color is (marginally) diffe
| ----- | ----------- |
| `markup.accent.codelens.lsp` | Accent color for code lens annotations |
| `markup.accent.codeaction.lsp` | Accent color for code action annotations |

### Inline Completions

| scope | description |
| ----- | ----------- |
| `meta.inline-completion.lsp` | Style for inline completions |
6 changes: 6 additions & 0 deletions docs/src/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ Inlay hints are disabled by default and can be enabled with the `"show_inlay_hin

!!! info "Some servers require additional settings to be enabled in order to show inlay hints."

## Inline Completions

Inline completions are typically provided by an AI code assistant.
They can span multiple lines and are rendered directly in the source code as grayed out text ("ghost text").
Currently inline completions are only requested when you manually trigger auto-completions (<kbd>Ctrl</kbd> + <kbd>Space</kbd>).

## Server Commands

In Sublime Text you can bind any runnable command to a key or add it to various UI elements. Commands in Sublime Text are normally supplied by plugins or packages written in Python. A language server may provide a runnable command as well. These kinds of commands are wrapped in an `lsp_execute` Sublime command that you can bind to a key.
Expand Down
63 changes: 63 additions & 0 deletions docs/src/language_servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,69 @@ If there are no setup steps for a language server on this page, but a [language
!!! info "For legacy ST3 docs, see [lsp.readthedocs.io](https://lsp.readthedocs.io)."


## Universal

### Tabby

[Tabby](https://tabby.tabbyml.com/) is a self-hosted AI coding assistant which can provide inline completions for [various programming languages](https://tabby.tabbyml.com/docs/references/programming-languages/).

In order to use Tabby you need a sufficiently fast GPU; the CPU version which can also be downloaded from the GitHub releases page is much too slow and it will result in timeouts for the completion requests.
Alternatively, Tabby can be setup on a separate server with capable hardware; see the [Configuration docs](https://tabby.tabbyml.com/docs/extensions/configurations/) for the required configuration details.
The following steps describe a local installation on a PC with compatible Nvidia GPU on Windows. More installation methods and the steps for other operation systems are listed in the [Tabby docs](https://tabby.tabbyml.com/docs/quick-start/installation/docker/).

1. Download and install the CUDA Toolkit from https://developer.nvidia.com/cuda-downloads

2. Download and extract a CUDA version of Tabby from the [GitHub releases page](https://github.com/TabbyML/tabby/releases) (click on "Assets"); e.g. `tabby_x86_64-windows-msvc-cuda122.zip`

3. Install the `tabby-agent` language server via npm (requires NodeJS):

```sh
npm install -g tabby-agent
```

4. Open `Preferences > Package Settings > LSP > Settings` and add the `"tabby"` client configuration to the `"clients"`:

```jsonc
{
"clients": {
"tabby": {
"enabled": true,
"command": ["tabby-agent", "--stdio"],
"selector": "source.js | source.python | source.rust", // replace with your relevant filetype(s)
"disabled_capabilities": {
"completionProvider": true
}
},
}
}
```

5. Download a completion model (see https://tabby.tabbyml.com/docs/models/ for available model files and GPU requirements):

```sh
tabby download --model StarCoder-1B
```

6. If necessary, edit the configuration file under `~/.tabby-client/agent/config.toml`, which is generated automatically on the first start of tabby-agent.
For example, to disable anonymous usage tracking add

```toml
[anonymousUsageTracking]
disable = true
```

7. Manually start the Tabby backend:

```sh
tabby serve --model StarCoder-1B --no-webserver
```

The language server communicates with this backend, i.e. it needs to be running in order for `tabby-agent` to work.

8. Now you can open a file in Sublime Text and start coding.
Inline completions are requested when you manually trigger auto-complete via <kbd>Ctrl</kbd> + <kbd>Space</kbd>.


## Angular

Follow installation instructions on [LSP-angular](https://github.com/sublimelsp/LSP-angular).
Expand Down
10 changes: 10 additions & 0 deletions plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
from enum import IntEnum, IntFlag
from typing import Any, Callable, Generator, List, Protocol, TypeVar
from typing import cast
from typing import TYPE_CHECKING
from typing_extensions import TypeAlias, TypeGuard
from weakref import WeakSet
import functools
Expand All @@ -122,6 +123,11 @@
import sublime
import weakref


if TYPE_CHECKING:
from ..inline_completion import InlineCompletionData


InitCallback: TypeAlias = Callable[['Session', bool], None]
T = TypeVar('T')

Expand Down Expand Up @@ -325,6 +331,9 @@ def get_initialize_params(variables: dict[str, str], workspace_folders: list[Wor
"itemDefaults": ["editRange", "insertTextFormat", "data"]
}
},
"inlineCompletion": {
"dynamicRegistration": True
},
"signatureHelp": {
"dynamicRegistration": True,
"contextSupport": True,
Expand Down Expand Up @@ -701,6 +710,7 @@ class AbstractViewListener(metaclass=ABCMeta):

view = cast(sublime.View, None)
hover_provider_count = 0
inline_completion = cast('InlineCompletionData', None)

@abstractmethod
def session_async(self, capability: str, point: int | None = None) -> Session | None:
Expand Down
8 changes: 8 additions & 0 deletions plugin/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from .core.windows import WindowManager
from .folding_range import folding_range_to_range
from .hover import code_actions_content
from .inline_completion import InlineCompletionData
from .session_buffer import SessionBuffer
from .session_view import SessionView
from functools import partial
Expand Down Expand Up @@ -197,6 +198,7 @@ def on_change() -> None:
self._stored_selection: list[sublime.Region] = []
self._should_format_on_paste = False
self.hover_provider_count = 0
self.inline_completion = InlineCompletionData(self.view, 'lsp_inline_completion')
self._setup()

def __del__(self) -> None:
Expand Down Expand Up @@ -226,6 +228,7 @@ def _cleanup(self) -> None:
self._stored_selection = []
self.view.erase_status(AbstractViewListener.TOTAL_ERRORS_AND_WARNINGS_STATUS_KEY)
self._clear_highlight_regions()
self.inline_completion.clear_async()
self._clear_session_views_async()

def _reset(self) -> None:
Expand Down Expand Up @@ -418,6 +421,7 @@ def on_selection_modified_async(self) -> None:
if not self._is_in_higlighted_region(first_region.b):
self._clear_highlight_regions()
self._clear_code_actions_annotation()
self.inline_completion.clear_async()
if userprefs().document_highlight_style or userprefs().show_code_actions:
self._when_selection_remains_stable_async(
self._on_selection_modified_debounced_async, first_region, after_ms=self.debounce_time)
Expand Down Expand Up @@ -511,6 +515,8 @@ def on_query_context(self, key: str, operator: int, operand: Any, match_all: boo
if not session_view:
return not operand
return operand == bool(session_view.session_buffer.get_document_link_at_point(self.view, position))
elif key == 'lsp.inline_completion_visible' and operator == sublime.QueryOperator.EQUAL:
return operand == self.inline_completion.visible
return None

@requires_session
Expand Down Expand Up @@ -560,6 +566,7 @@ def _on_hover_gutter_async(self, point: int) -> None:
def on_text_command(self, command_name: str, args: dict | None) -> tuple[str, dict] | None:
if command_name == "auto_complete":
self._auto_complete_triggered_manually = True
self.view.run_command('lsp_inline_completion')
elif command_name == "show_scope_name" and userprefs().semantic_highlighting:
session = self.session_async("semanticTokensProvider")
if session:
Expand Down Expand Up @@ -990,6 +997,7 @@ def _on_view_updated_async(self) -> None:
if first_region is None:
return
self._clear_highlight_regions()
self.inline_completion.clear_async()
if userprefs().document_highlight_style:
self._when_selection_remains_stable_async(
self._do_highlights_async, first_region, after_ms=self.debounce_time)
Expand Down
Loading

0 comments on commit 57f6a30

Please sign in to comment.