From aa6b933a14b6b800fa97a3768154ad49fe411831 Mon Sep 17 00:00:00 2001 From: Zhiming Ma Date: Mon, 30 Sep 2024 21:06:05 +0800 Subject: [PATCH] feat(eclipse): add preferences page. (#3225) --- clients/eclipse/feature/feature.xml | 4 +- clients/eclipse/plugin/META-INF/MANIFEST.MF | 2 +- clients/eclipse/plugin/images/settings.png | Bin 0 -> 817 bytes clients/eclipse/plugin/images/settings@2x.png | Bin 0 -> 1855 bytes clients/eclipse/plugin/plugin.xml | 9 ++ .../src/com/tabbyml/tabby4eclipse/Images.java | 1 + .../com/tabbyml/tabby4eclipse/Startup.java | 3 + .../commands/OpenPreferences.java | 16 +++ .../BasicInputEventTrigger.java | 2 +- .../DebouncedDocumentEventTrigger.java | 2 +- .../IInlineCompletionService.java | 6 +- .../InlineCompletionService.java | 22 +-- .../PairedDocumentEventTrigger.java | 4 +- .../tabby4eclipse/lsp/ConnectionProvider.java | 42 ++++-- .../preferences/MainPreferencesPage.java | 129 ++++++++++++++++++ .../preferences/PreferencesService.java | 92 +++++++++++++ .../statusbar/StatusbarContribution.java | 23 ++++ 17 files changed, 327 insertions(+), 30 deletions(-) create mode 100644 clients/eclipse/plugin/images/settings.png create mode 100644 clients/eclipse/plugin/images/settings@2x.png create mode 100644 clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/commands/OpenPreferences.java create mode 100644 clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/MainPreferencesPage.java create mode 100644 clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/PreferencesService.java diff --git a/clients/eclipse/feature/feature.xml b/clients/eclipse/feature/feature.xml index 1306a58484f..fa61eaaaae2 100644 --- a/clients/eclipse/feature/feature.xml +++ b/clients/eclipse/feature/feature.xml @@ -2,7 +2,7 @@ @@ -19,6 +19,6 @@ + version="0.0.2.21"/> diff --git a/clients/eclipse/plugin/META-INF/MANIFEST.MF b/clients/eclipse/plugin/META-INF/MANIFEST.MF index fd94d25580a..db827141563 100644 --- a/clients/eclipse/plugin/META-INF/MANIFEST.MF +++ b/clients/eclipse/plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Tabby Plugin for Eclipse Bundle-SymbolicName: com.tabbyml.tabby4eclipse;singleton:=true -Bundle-Version: 0.0.2.20 +Bundle-Version: 0.0.2.21 Bundle-Activator: com.tabbyml.tabby4eclipse.Activator Bundle-Vendor: com.tabbyml Require-Bundle: org.eclipse.ui, diff --git a/clients/eclipse/plugin/images/settings.png b/clients/eclipse/plugin/images/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..3e17f5861055c9a797173fbd98f9f5a935998841 GIT binary patch literal 817 zcmV-11J3-3P)@_TyV{XU=f`GrFlO;1nX6GibA%d%NP5d8c5`^y*kuxEyr9>j}EEo*lWm%SDSr&Mn=Ojt;M<-QV$eoWn2-9LH%f41>`$P4hetwr#5n!(6RYD%F{pnfu$@+n+H2 z07;S_OOhlF4h~|nEOXUrRV$avuL*(}vn*?3YisL^qA1$Hz(BtwNw_S_{lQ@H2>^f_ z0HD!m{POvH#}q}m4-O7csZ@Hmu(0sxOslu2rlxY?a5xhRg&0lK{vd>E{|s|}etvFs zb@gO+c6O)RVDtI>X1QEG$>nk{+Ml<#;5d$B^E?lRVd&ieE|<$VJUj$~AgTaxd=}7y z<9Lwgc_0X)N0w#keDe7CxX0u1`0DjKP!#0{0J^hAS(XdgY&Hb|;Pd&sj^o@~Sy_2| z7LdtgK6$;~>!xX9mSx>!80LziC?DMb00<%d=;#P++Xj*(@jxID&*$?$_V)HZ=(=7N zMRAg*=?FpyH%${v(*&2xwbQAf)oQJ|-R=pJBpbC_Z4CfMXqxVI94E$cT!JJ?N!N8^ zadB}IA!Ie1&9b5>4^>sQJLk#se5hWp?*M?2N~InQ4-d}`4Gs00rU?ikwNNNLFBXe$ z0Dv1E9X%7`VU;_YDDwS_uuXnPqukTv3*#uqJ-!CmKJw1JIXqwh+=XC(* vMUo`Gv9WR4FpRGZ!@OKyU;o+7`(OGC5&RP9joebq00000NkvXXu0mjfNbGIP literal 0 HcmV?d00001 diff --git a/clients/eclipse/plugin/images/settings@2x.png b/clients/eclipse/plugin/images/settings@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c487c260cb91eaf73093321cd06c52008a0bc01a GIT binary patch literal 1855 zcmV-F2f+A=P)8`%}d|D!vj(Ma~lcJNyAD)C30jbb@<-8v}U zEHo`_OhPvw?A9--*_1Ri;A~sk;=Y!O7Z=-6f_? zlSZ~|*|DOLwUMQfERE+&w-4DdvMqP5hrac|f#GuR`Tyq3nS0M=P`=rM!C<#6%Lmix z^j9;PjE_>PI2?`#sZ{D`021W{W6D)Oc<>U=J zRrRBC;<4odG&D2>-EOz&bUMMZELfJswr$%0fSZ|_IkK>@@IM7$91h1JQ53;(+$sRe zvS?{(fz4+71^@!U+-g9w$v9sk$PT~Xe4YE%Ydn!i(1#BnuEgWimk-~V1uPtR|ws;Zb$DSq5e&M+OE4K3!is0MOIZ^W8mr_Izl!+qt7hkCIZE7#tj=y}iBn)9Lg#*JOZF`ig0q z`SsL-ARrozf>LTuPEK}gCJq4CuV4Sm?c2A%9u9}KP$-1rOfU=sRaFs-#dOm&YgUWS zdPpXd(=0A;+91skecsWW@b(Scwx=8ty`;JyLN4uVhCxe*t5fCSNXq!{KmKN{ONgsBHMMXt>xd64bwVjkwE}zfCG))+WkpW<=pSLC@9LMcDefsq88yg#6vudETvlCvg zxAXY%<5gP~KYaLbZEI`mUWQ?yC<^lVJXBTv%K7u>e+}T(;<>B8AtB^=Fc|#9g$oxt zJsuA@jzghP0LO6%hr@;-2yLUIqkq~8z{!&*Kjt{j$FeNZG!2%!T&}NGR#rAoO-=pN zG|d-l0Gv+ey-Sxa?bx+z7YxHd@j{Qs!%|9jwzaiY+`oT+=)Z~g_4WO7|Ni~o%jffK zp-@;8N7r?@-EO}mNqi!a7+3>fx7+JH9#2PmdpoCT+Un+^X&M-Y0mCq)xw$!b=+L2V zpU-!5VqzjyEPVFt*;h`SIPu3oAn^Ug#YK(~vPRtUbUK~AckkYLMNuNa+SAbM^?E07 z+_+K4^E?d0fMFO`0l_c~EH5u3nM@iUkH;1Yg(OLm9%ZxH9LI5u9*-yBa=C1T5Id!` zs!#SO_arF5IBs)6?QcEKXf<#Mnp`HPycWilB?mSqt@3(xbd zUaz;_<#MqAh_36FMcrBaz7JPPnEc(slh)Ns`{EuCCrG zNs<(c#RhCP+b5h($osEr+B~zTs z`|bP+E*pLzhV`FuWKG#dRY*7b_z-V54x@811UZ*OmtC0Yy-i^cwY z`SRtT0*C>iTM1ZhTmG+HF1H{_Qd31m1&SebUB}AG$`F9( zTkN7J-YhrXX7_?kEuYUDs;a&fjYjRVEE7dhpsH$K*Y(LOSFU`3EvDYGvhRj?dBJ!c tfZuMnzsfL7R8`eU01E)( + + + + + { logger.debug("Trigger inline completion after debouncing."); - inlineCompletionService.trigger(); + inlineCompletionService.trigger(false); }); } catch (Exception e) { logger.error("Failed to handle documentChangedRunnable after debouncing.", e); diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/IInlineCompletionService.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/IInlineCompletionService.java index b09ab5a607c..062400770f2 100644 --- a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/IInlineCompletionService.java +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/IInlineCompletionService.java @@ -20,9 +20,11 @@ public interface IInlineCompletionService { /** * Trigger an inline completion request at the current caret position of the - * active text editor. + * active text editor. + * + * @param isManualTrigger whether to trigger manually or automatically */ - public void trigger(); + public void trigger(boolean isManualTrigger); /** * Accept the current completion item ghost text. diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/InlineCompletionService.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/InlineCompletionService.java index 82993fc1b26..575f3be1410 100644 --- a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/InlineCompletionService.java +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/InlineCompletionService.java @@ -23,6 +23,7 @@ import com.tabbyml.tabby4eclipse.lsp.protocol.ITelemetryService; import com.tabbyml.tabby4eclipse.lsp.protocol.ITextDocumentServiceExt; import com.tabbyml.tabby4eclipse.lsp.protocol.InlineCompletionParams; +import com.tabbyml.tabby4eclipse.preferences.PreferencesService; public class InlineCompletionService implements IInlineCompletionService { public static IInlineCompletionService getInstance() { @@ -62,7 +63,11 @@ public boolean isValid() { } @Override - public void trigger() { + public void trigger(boolean isManualTrigger) { + boolean autoTriggerEnabled = PreferencesService.getInstance().getInlineCompletionTriggerAuto(); + if (!autoTriggerEnabled && !isManualTrigger) { + return; + } ITextEditor textEditor = EditorUtils.getActiveTextEditor(); int offset = EditorUtils.getCurrentOffsetInDocument(textEditor); long modificationStamp = EditorUtils.getDocumentModificationStamp(textEditor); @@ -79,7 +84,7 @@ public void trigger() { ITextViewer textViewer = EditorUtils.getTextViewer(textEditor); InlineCompletionContext.Request request = new InlineCompletionContext.Request(textEditor, offset, - modificationStamp); + modificationStamp, isManualTrigger); InlineCompletionParams params = request.toInlineCompletionParams(); if (params == null) { return; @@ -118,7 +123,7 @@ public void accept() { int offset = current.request.offset; InlineCompletionItem item = current.response.getActiveCompletionItem(); EventParams eventParams = buildTelemetryEventParams(EventParams.Type.SELECT); - + renderer.hide(); current = null; @@ -162,7 +167,7 @@ public void dismiss() { private EventParams buildTelemetryEventParams(String type) { return buildTelemetryEventParams(type, null); } - + private EventParams buildTelemetryEventParams(String type, String selectKind) { InlineCompletionItem item = this.renderer.getCurrentCompletionItem(); if (item != null && item == current.response.getActiveCompletionItem()) { @@ -176,12 +181,11 @@ private EventParams buildTelemetryEventParams(String type, String selectKind) { } return null; } - + private void postTelemetryEvent(EventParams params) { if (params != null) { LanguageServerService.getInstance().getServer().execute((server) -> { - ITelemetryService telemetryService = ((ILanguageServer) server) - .getTelemetryService(); + ITelemetryService telemetryService = ((ILanguageServer) server).getTelemetryService(); telemetryService.event(params); return null; }); @@ -198,12 +202,12 @@ private static class Request { private long modificationStamp; private boolean manually; - public Request(ITextEditor textEditor, int offset, long modificationStamp) { + public Request(ITextEditor textEditor, int offset, long modificationStamp, boolean manually) { this.textEditor = textEditor; this.document = EditorUtils.getDocument(textEditor); this.offset = offset; this.modificationStamp = modificationStamp; - this.manually = false; + this.manually = manually; } public InlineCompletionParams toInlineCompletionParams() { diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/PairedDocumentEventTrigger.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/PairedDocumentEventTrigger.java index 8df42bcc85f..b4cc196316a 100644 --- a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/PairedDocumentEventTrigger.java +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/inlineCompletion/PairedDocumentEventTrigger.java @@ -99,7 +99,7 @@ private void handleCaretMoved(ITextEditor textEditor, CaretEvent event) { if (pendingEvent != null && pendingEvent.textEditor == textEditor) { if (pendingEvent.documentEvent != null && pendingEvent.modificationStamp == modificationStamp) { logger.debug("Received caretEvent with paired documentEvent, trigger inline completion."); - inlineCompletionService.trigger(); + inlineCompletionService.trigger(false); pendingEvent = null; } else { logger.debug("Received caretEvent, waiting for paired documentEvent."); @@ -130,7 +130,7 @@ private void handleDocumentChanged(ITextEditor textEditor, DocumentEvent event) if (pendingEvent != null && pendingEvent.textEditor == textEditor) { if (pendingEvent.caretEvent != null && pendingEvent.modificationStamp == modificationStamp) { logger.debug("Received documentEvent with paired caretEvent, trigger inline completion."); - inlineCompletionService.trigger(); + inlineCompletionService.trigger(false); pendingEvent = null; } else { logger.debug("Received documentEvent, waiting for paired caretEvent."); diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/lsp/ConnectionProvider.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/lsp/ConnectionProvider.java index 080d5508fc6..e3e4623cd77 100644 --- a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/lsp/ConnectionProvider.java +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/lsp/ConnectionProvider.java @@ -23,6 +23,7 @@ import com.tabbyml.tabby4eclipse.lsp.protocol.ClientInfo.TabbyPluginInfo; import com.tabbyml.tabby4eclipse.lsp.protocol.ClientProvidedConfig; import com.tabbyml.tabby4eclipse.lsp.protocol.InitializationOptions; +import com.tabbyml.tabby4eclipse.preferences.PreferencesService; public class ConnectionProvider extends ProcessStreamConnectionProvider { private Logger logger = new Logger("ConnectionProvider"); @@ -31,24 +32,42 @@ public ConnectionProvider() { try { // Find node executable File nodeExecutableFile = null; - String systemPath = System.getenv("PATH"); - logger.debug("System env PATH: " + systemPath); - if (systemPath != null) { - String[] paths = systemPath.split(File.pathSeparator); - for (String p : paths) { - File file = new File(p, Utils.isWindows() ? "node.exe" : "node"); - if (file.exists() && file.canExecute()) { - nodeExecutableFile = file; - logger.debug("Node executable: " + file.getAbsolutePath()); - break; + + String nodePathFromPreference = PreferencesService.getInstance().getNodeBinaryPath(); + if (nodePathFromPreference != null && !nodePathFromPreference.isEmpty()) { + String nodePath = nodePathFromPreference.replaceFirst("~", System.getProperty("user.home")); + logger.info("Node executable path from preference: " + nodePath); + File file = new File(nodePath); + if (file.exists() && file.canExecute()) { + nodeExecutableFile = file; + } else { + logger.info("Cannot find node executable in: " + nodePath); + } + } + + if (nodeExecutableFile == null) { + String systemPath = System.getenv("PATH"); + logger.info("Finding node executable in system paths: " + systemPath); + if (systemPath != null) { + String[] paths = systemPath.split(File.pathSeparator); + for (String p : paths) { + File file = new File(p, Utils.isWindows() ? "node.exe" : "node"); + if (file.exists() && file.canExecute()) { + nodeExecutableFile = file; + break; + } } } } + if (nodeExecutableFile == null) { StatusInfoHolder.getInstance().setConnectionFailed(true); logger.error("Cannot find node executable."); return; + } else { + logger.info("Using node executable: " + nodeExecutableFile.getAbsolutePath()); } + // Find tabby-agent script Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID); URL agentScriptUrl = FileLocator.find(bundle, new Path("tabby-agent/dist/node/index.js")); @@ -87,8 +106,7 @@ public void stop() { } private ClientProvidedConfig getProvidedConfig() { - ClientProvidedConfig config = new ClientProvidedConfig(); - return config; + return PreferencesService.getInstance().buildClientProvidedConfig(); } private ClientInfo getClientInfo() { diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/MainPreferencesPage.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/MainPreferencesPage.java new file mode 100644 index 00000000000..dc38be424bf --- /dev/null +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/MainPreferencesPage.java @@ -0,0 +1,129 @@ +package com.tabbyml.tabby4eclipse.preferences; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.PreferenceDialog; +import org.eclipse.jface.preference.StringFieldEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.PreferencesUtil; + +import com.tabbyml.tabby4eclipse.Activator; + +public class MainPreferencesPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + public static final String ID = "com.tabbyml.tabby4eclipse.preferences.main"; + + public static void openPreferences() { + PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn( + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), MainPreferencesPage.ID, + new String[] { MainPreferencesPage.ID, "org.eclipse.lsp4e.preferences", + "org.eclipse.lsp4e.logging.preferences", "org.eclipse.ui.preferencePages.Keys" }, + (Object) null); + if (dialog != null) { + dialog.open(); + } + } + + public MainPreferencesPage() { + super(GRID); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + } + + @Override + public void createFieldEditors() { + Composite parent = getFieldEditorParent(); + createServerGroup(parent); + createCompletionGroup(parent); + createEnvironmentGroup(parent); + createTelemetryGroup(parent); + } + + private void createServerGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).span(2, 1).applyTo(group); + group.setText("Server"); + group.setLayout(new GridLayout()); + + Composite grid = new Composite(group, SWT.NONE); + grid.setLayout(new GridLayout(2, false)); + + StringFieldEditor endpointInput = new StringFieldEditor(PreferencesService.KEY_SERVER_ENDPOINT, "Endpoint", + grid); + addField(endpointInput); + StringFieldEditor tokenInput = new StringFieldEditor(PreferencesService.KEY_SERVER_TOKEN, "Token", grid); + tokenInput.getTextControl(grid).setEchoChar('*'); + addField(tokenInput); + + Label tip = new Label(grid, SWT.WRAP); + tip.setText( + "Note: If leave empty, server endpoint config in `~/.tabby-client/agent/config.toml` will be used."); + GridDataFactory.fillDefaults().indent(10, 2).span(2, 1).applyTo(tip); + } + + private void createCompletionGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).span(2, 1).applyTo(group); + group.setText("Completion"); + group.setLayout(new GridLayout()); + + Composite grid = new Composite(group, SWT.NONE); + grid.setLayout(new GridLayout(2, false)); + + BooleanFieldEditor autoTriggerCheckbox = new BooleanFieldEditor( + PreferencesService.KEY_INLINE_COMPLETION_TRIGGER_AUTO, "Automatically trigger inline completion", grid); + addField(autoTriggerCheckbox); + } + + private void createEnvironmentGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).span(2, 1).applyTo(group); + group.setText("Environment"); + group.setLayout(new GridLayout()); + + Composite grid = new Composite(group, SWT.NONE); + grid.setLayout(new GridLayout(2, false)); + + StringFieldEditor nodeBinaryPathInput = new StringFieldEditor(PreferencesService.KEY_NODE_BINARY_PATH, + "Node.js binary path", grid); + addField(nodeBinaryPathInput); + + Label tip = new Label(grid, SWT.WRAP); + tip.setText( + "Tabby will attempt to find the Node binary in the `PATH` environment variable for running tabby-agent.\nYou can specify the path to the Node.js binary here if required. Restart IDE to take effect."); + GridDataFactory.fillDefaults().indent(10, 2).span(2, 1).applyTo(tip); + } + + private void createTelemetryGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).span(2, 1).applyTo(group); + group.setText("Telemetry"); + group.setLayout(new GridLayout()); + + Composite grid = new Composite(group, SWT.NONE); + grid.setLayout(new GridLayout(2, false)); + + BooleanFieldEditor disableAnonymousUsageTrackingCheckbox = new BooleanFieldEditor( + PreferencesService.KEY_ANONYMOUS_USAGE_TRACKING_DISABLED, "Disable anonymous usage tracking", grid); + addField(disableAnonymousUsageTrackingCheckbox); + + Label tip = new Label(grid, SWT.WRAP); + tip.setText( + "Tabby collects aggregated anonymous usage data and sends it to the Tabby team to help improve our products.\nYour code, generated completions, or any identifying information is never tracked or transmitted.\nFor more details on data collection, please check our online documentation."); + GridDataFactory.fillDefaults().indent(10, 2).span(2, 1).applyTo(tip); + } + + @Override + public void init(IWorkbench workbench) { + } +} diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/PreferencesService.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/PreferencesService.java new file mode 100644 index 00000000000..2b970540338 --- /dev/null +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/preferences/PreferencesService.java @@ -0,0 +1,92 @@ +package com.tabbyml.tabby4eclipse.preferences; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.lsp4j.DidChangeConfigurationParams; +import org.eclipse.lsp4j.services.WorkspaceService; + +import com.tabbyml.tabby4eclipse.Activator; +import com.tabbyml.tabby4eclipse.Logger; +import com.tabbyml.tabby4eclipse.lsp.LanguageServerService; +import com.tabbyml.tabby4eclipse.lsp.protocol.ClientProvidedConfig; +import com.tabbyml.tabby4eclipse.lsp.protocol.ILanguageServer; + +public class PreferencesService { + public static final String KEY_SERVER_ENDPOINT = "SERVER_ENDPOINT"; + public static final String KEY_SERVER_TOKEN = "SERVER_TOKEN"; + public static final String KEY_INLINE_COMPLETION_TRIGGER_AUTO = "INLINE_COMPLETION_TRIGGER_AUTO"; + public static final String KEY_NODE_BINARY_PATH = "NODE_BINARY_PATH"; + public static final String KEY_ANONYMOUS_USAGE_TRACKING_DISABLED = "ANONYMOUS_USAGE_TRACKING_DISABLED"; + + public static PreferencesService getInstance() { + return LazyHolder.INSTANCE; + } + + private static class LazyHolder { + private static final PreferencesService INSTANCE = new PreferencesService(); + } + + private Logger logger = new Logger("PreferencesService"); + + public void init() { + getPreferenceStore().setDefault(KEY_INLINE_COMPLETION_TRIGGER_AUTO, true); + + getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + logger.info("Syncing configuration."); + LanguageServerService.getInstance().getServer().execute((server) -> { + WorkspaceService workspaceService = ((ILanguageServer) server).getWorkspaceService(); + DidChangeConfigurationParams params = new DidChangeConfigurationParams(); + params.setSettings(buildClientProvidedConfig()); + workspaceService.didChangeConfiguration(params); + return null; + }); + } + }); + } + + public IPreferenceStore getPreferenceStore() { + return Activator.getDefault().getPreferenceStore(); + } + + public ClientProvidedConfig buildClientProvidedConfig() { + ClientProvidedConfig config = new ClientProvidedConfig(); + + ClientProvidedConfig.ServerConfig serverConfig = new ClientProvidedConfig.ServerConfig(getServerEndpoint(), + getServerToken()); + config.setServer(serverConfig); + + ClientProvidedConfig.InlineCompletionConfig inlineCompletionConfig = new ClientProvidedConfig.InlineCompletionConfig( + getInlineCompletionTriggerAuto() ? ClientProvidedConfig.InlineCompletionConfig.TriggerMode.AUTO + : ClientProvidedConfig.InlineCompletionConfig.TriggerMode.MANUAL); + config.setInlineCompletion(inlineCompletionConfig); + + ClientProvidedConfig.AnonymousUsageTrackingConfig anonymousUsageTrackingConfig = new ClientProvidedConfig.AnonymousUsageTrackingConfig( + getAnonymousUsageTrackingDisabled()); + config.setAnonymousUsageTracking(anonymousUsageTrackingConfig); + + return config; + } + + public String getServerEndpoint() { + return getPreferenceStore().getString(KEY_SERVER_ENDPOINT); + } + + public String getServerToken() { + return getPreferenceStore().getString(KEY_SERVER_TOKEN); + } + + public boolean getInlineCompletionTriggerAuto() { + return getPreferenceStore().getBoolean(KEY_INLINE_COMPLETION_TRIGGER_AUTO); + } + + public String getNodeBinaryPath() { + return getPreferenceStore().getString(KEY_NODE_BINARY_PATH); + } + + public boolean getAnonymousUsageTrackingDisabled() { + return getPreferenceStore().getBoolean(KEY_ANONYMOUS_USAGE_TRACKING_DISABLED); + } +} diff --git a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/statusbar/StatusbarContribution.java b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/statusbar/StatusbarContribution.java index f3d7da9c69b..35d1165f6aa 100644 --- a/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/statusbar/StatusbarContribution.java +++ b/clients/eclipse/plugin/src/com/tabbyml/tabby4eclipse/statusbar/StatusbarContribution.java @@ -19,6 +19,7 @@ import com.tabbyml.tabby4eclipse.lsp.LanguageServerService; import com.tabbyml.tabby4eclipse.lsp.StatusInfoHolder; import com.tabbyml.tabby4eclipse.lsp.protocol.StatusInfo; +import com.tabbyml.tabby4eclipse.preferences.MainPreferencesPage; public class StatusbarContribution extends WorkbenchWindowControlContribution { private static final String TOOLTIP_INITIALIZATION_FAILED = "Tabby: Initialization Failed"; @@ -72,6 +73,12 @@ private void updateLabel(CLabel label) { case StatusInfo.Status.READY: label.setImage(Images.getIcon(Images.ICON_CHECK)); break; + case StatusInfo.Status.READY_FOR_AUTO_TRIGGER: + label.setImage(Images.getIcon(Images.ICON_CHECK)); + break; + case StatusInfo.Status.READY_FOR_MANUAL_TRIGGER: + label.setImage(Images.getIcon(Images.ICON_CHECK)); + break; case StatusInfo.Status.FETCHING: label.setImage(Images.getIcon(Images.ICON_LOADING)); break; @@ -126,6 +133,12 @@ public void widgetSelected(SelectionEvent e) { case StatusInfo.Status.READY: statusItem.setImage(Images.getIcon(Images.ICON_CHECK)); break; + case StatusInfo.Status.READY_FOR_AUTO_TRIGGER: + statusItem.setImage(Images.getIcon(Images.ICON_CHECK)); + break; + case StatusInfo.Status.READY_FOR_MANUAL_TRIGGER: + statusItem.setImage(Images.getIcon(Images.ICON_CHECK)); + break; case StatusInfo.Status.FETCHING: statusItem.setImage(Images.getIcon(Images.ICON_LOADING)); break; @@ -147,6 +160,16 @@ public void widgetSelected(SelectionEvent e) { } }); + MenuItem openPreferencesItem = new MenuItem(menu, SWT.NONE); + openPreferencesItem.setImage(Images.getIcon(Images.ICON_SETTINGS)); + openPreferencesItem.setText("Open Settings"); + openPreferencesItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + MainPreferencesPage.openPreferences(); + } + }); + return menu; } }