diff --git a/src/configReader.ts b/src/configReader.ts new file mode 100644 index 000000000..ec731e919 --- /dev/null +++ b/src/configReader.ts @@ -0,0 +1,59 @@ +import { workspace, WorkspaceConfiguration } from 'vscode'; + +export interface ColorsConfig { + disconnected: string, + launching: string, + connected: string, + typeStatus: string, + active: string, + inactive: string, + error: string +} + +export class ConfigReader { + private changeEventDisposable; + constructor() { + this.changeEventDisposable = workspace.onDidChangeConfiguration(configChange => { + if(configChange.affectsConfiguration("calva.statusColor")){ + this._colors = this.readColorConfig(); + } + }); + } + + private _colors: ColorsConfig; + + get colors() { + if(this._colors === undefined){ + this._colors = this.readColorConfig(); + } + return this._colors; + } + + private readColorConfig(): ColorsConfig { + let colorConfig = workspace.getConfiguration('calva.statusColor'); + return { + disconnected: this.colorValue("disconnectedColor", colorConfig), + launching: this.colorValue("launchingColor", colorConfig), + // TODO: Fix config typo + connected: this.colorValue("connectedSatusColor", colorConfig), + typeStatus: this.colorValue("typeStatusColor", colorConfig), + // TODO: Create config entries + active: "white", + inactive: "#b3b3b3", + error: "#FF2D00" + } + } + + private colorValue(section: string, currentConf: WorkspaceConfiguration):string { + let { defaultValue, globalValue, workspaceFolderValue, workspaceValue} = currentConf.inspect(section); + return workspaceFolderValue || workspaceValue || globalValue || defaultValue; + } + + dispose() { + this.changeEventDisposable.dispose(); + } +} + +// TODO: This should be somewhere else +const configReader = new ConfigReader(); +export default configReader; diff --git a/src/extension.ts b/src/extension.ts index 68316677c..37838971d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode'; +import configReader from "./configReader"; import * as paredit from "./paredit/extension"; import * as fmt from "./calva-fmt/src/extension"; import * as highlight from "./highlight/src/extension"; @@ -54,6 +55,8 @@ function onDidOpen(document) { function activate(context: vscode.ExtensionContext) { + context.subscriptions.push(configReader); + state.cursor.set('analytics', new Analytics(context)); state.analytics().logPath("/start").logEvent("LifeCycle", "Started").send(); @@ -104,7 +107,9 @@ function activate(context: vscode.ExtensionContext) { chan.appendLine("Calva activated."); - status.update(); + const statusbars = statusbar.init(); + context.subscriptions.push(...statusbars); + util.updateREPLSessionType(); // COMMANDS context.subscriptions.push(vscode.commands.registerCommand('calva.jackInOrConnect', jackIn.calvaJackInOrConnect)); @@ -159,7 +164,7 @@ function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.languages.registerHoverProvider(state.documentSelector, new HoverProvider())); context.subscriptions.push(vscode.languages.registerDefinitionProvider(state.documentSelector, new DefinitionProvider())); context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(state.documentSelector, new CalvaSignatureHelpProvider(), ' ', ' ')); - + vscode.workspace.registerTextDocumentContentProvider('jar', new TextDocumentContentProvider()); diff --git a/src/paredit/statusbar.ts b/src/paredit/statusbar.ts index 747b42669..b4f99c9b8 100644 --- a/src/paredit/statusbar.ts +++ b/src/paredit/statusbar.ts @@ -1,6 +1,6 @@ 'use strict'; import { window, StatusBarAlignment, StatusBarItem } from 'vscode'; -import statusbar from '../statusbar'; +import configReader from "../configReader"; import * as paredit from './extension'; export class StatusBar { @@ -22,7 +22,7 @@ export class StatusBar { paredit.onPareditKeyMapChanged((keymap) => { this.keyMap = keymap; - }) + }) } get keyMap() { @@ -30,7 +30,6 @@ export class StatusBar { } set keyMap(keymap: String) { - switch (keymap.trim().toLowerCase()) { case 'original': this._keyMap = 'original'; @@ -62,10 +61,11 @@ export class StatusBar { set enabled(value: Boolean) { this._enabled = value; + // NOTE: Changes to color config are not picked up if (this._enabled) { - this._toggleBarItem.color = statusbar.color.active; + this._toggleBarItem.color = configReader.colors.active; } else { - this._toggleBarItem.color = statusbar.color.inactive; + this._toggleBarItem.color = configReader.colors.inactive; } } @@ -84,4 +84,4 @@ export class StatusBar { dispose() { this._toggleBarItem.dispose(); } -} \ No newline at end of file +} diff --git a/src/state.ts b/src/state.ts index 8d03b73aa..b39422674 100644 --- a/src/state.ts +++ b/src/state.ts @@ -95,6 +95,7 @@ function _trimAliasName(name: string): string { return name.replace(/^[\s,:]*/, "").replace(/[\s,:]*$/, "") } +// TODO: Refactor config reader to provide all config values // TODO find a way to validate the configs function config() { let configOptions = vscode.workspace.getConfiguration('calva'); diff --git a/src/statusbar.ts b/src/statusbar.ts deleted file mode 100644 index be46f2b83..000000000 --- a/src/statusbar.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as vscode from 'vscode'; -import { activeReplWindow } from './repl-window'; -import * as state from './state'; -import * as util from './utilities'; - -const connectionStatus = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); -const typeStatus = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); -const cljsBuildStatus = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); -const prettyPrintToggle = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); -const color = { - active: "white", - inactive: "#b3b3b3" -}; - -function colorValue(section: string, currentConf: vscode.WorkspaceConfiguration):string { - let { defaultValue, globalValue, workspaceFolderValue, workspaceValue} = currentConf.inspect(section); - - return workspaceFolderValue || workspaceValue || globalValue || defaultValue; -} - -function update() { - - let currentConf = vscode.workspace.getConfiguration('calva.statusColor'); - - let current = state.deref(), - doc = util.getDocument({}), - fileType = util.getFileType(doc), - cljsBuild = current.get('cljsBuild'); - - //let disconnectedColor = "rgb(192,192,192)"; - - const pprint = state.config().prettyPrintingOptions.enabled; - prettyPrintToggle.text = "pprint"; - prettyPrintToggle.color = pprint ? color.active : color.inactive; - prettyPrintToggle.tooltip = `Turn pretty printing ${pprint ? 'off' : 'on'}` - prettyPrintToggle.command = "calva.togglePrettyPrint" - - typeStatus.command = null; - typeStatus.text = "Disconnected"; - typeStatus.tooltip = "No active REPL session"; - typeStatus.color = colorValue("disconnectedColor", currentConf); - - connectionStatus.command = null; - connectionStatus.tooltip = "REPL connection status"; - - cljsBuildStatus.text = null; - cljsBuildStatus.command = "calva.switchCljsBuild"; - cljsBuildStatus.tooltip = null; - - if (current.get('connected')) { - connectionStatus.text = "nREPL $(zap)"; - connectionStatus.color = colorValue("connectedSatusColor", currentConf); - connectionStatus.tooltip = `nrepl://${current.get('hostname')}:${current.get('port')} (Click to reset connection)`; - connectionStatus.command = "calva.jackInOrConnect"; - typeStatus.color = colorValue("typeStatusColor", currentConf); - if (fileType == 'cljc' && util.getREPLSessionType() !== null && !activeReplWindow()) { - typeStatus.text = "cljc/" + util.getREPLSessionType() - if (util.getSession('clj') !== null && util.getSession('cljs') !== null) { - typeStatus.command = "calva.toggleCLJCSession"; - typeStatus.tooltip = `Click to use ${(util.getREPLSessionType() === 'clj' ? 'cljs' : 'clj')} REPL for cljc`; - } - } else if (util.getREPLSessionType() === 'cljs') { - typeStatus.text = "cljs"; - typeStatus.tooltip = "Connected to ClojureScript REPL"; - } else if (util.getREPLSessionType() === 'clj') { - typeStatus.text = "clj" - typeStatus.tooltip = "Connected to Clojure REPL"; - } - if (util.getREPLSessionType() === 'cljs' && state.extensionContext.workspaceState.get('cljsReplTypeHasBuilds')) { - if (cljsBuild !== null && util.getREPLSessionType() === 'cljs') { - cljsBuildStatus.text = cljsBuild; - cljsBuildStatus.tooltip = "Click to switch CLJS build REPL"; - } else if (cljsBuild === null) { - cljsBuildStatus.text = "no build connected" - cljsBuildStatus.tooltip = "Click to connect to a CLJS build REPL"; - } - } - } else if (util.getLaunchingState()) { - connectionStatus.color = colorValue("launchingColor", currentConf); - connectionStatus.text = "Launching REPL using " + util.getLaunchingState(); - connectionStatus.tooltip = "Click to interrupt jack-in or Connect to REPL Server"; - connectionStatus.command = "calva.disconnect"; - } else if (util.getConnectingState()) { - connectionStatus.text = "nREPL - trying to connect"; - connectionStatus.tooltip = "Click to interrupt jack-in or Connect to REPL Server"; - connectionStatus.command = "calva.disconnect"; - } else { - connectionStatus.text = "nREPL $(zap)"; - connectionStatus.tooltip = "Click to jack-in or Connect to REPL Server"; - connectionStatus.color = colorValue("disconnectedColor", currentConf); - connectionStatus.command = "calva.jackInOrConnect"; - } - - connectionStatus.show(); - typeStatus.show(); - if (cljsBuildStatus.text) { - cljsBuildStatus.show(); - } else { - cljsBuildStatus.hide(); - } - prettyPrintToggle.show(); -} - -export default { - update, - color -}; diff --git a/src/statusbar/cljs-build.ts b/src/statusbar/cljs-build.ts new file mode 100644 index 000000000..537c02239 --- /dev/null +++ b/src/statusbar/cljs-build.ts @@ -0,0 +1,44 @@ +import { window, StatusBarAlignment, StatusBarItem } from "vscode"; +import * as state from '../state'; +import * as util from '../utilities'; + +export class CljsBuildStatusBarItem { + private statusBarItem: StatusBarItem; + constructor(alignment: StatusBarAlignment) { + this.statusBarItem = window.createStatusBarItem(alignment); + this.statusBarItem.command = "calva.switchCljsBuild"; + } + + update() { + const current = state.deref(); + const cljsBuild = current.get('cljsBuild'); + const connected = current.get("connected"); + const sessionType = util.getREPLSessionType(); + + let text = null; + let tooltip = null; + + if(connected && sessionType === 'cljs' && state.extensionContext.workspaceState.get('cljsReplTypeHasBuilds')) { + if (cljsBuild !== null) { + this.statusBarItem.text = cljsBuild; + this.statusBarItem.tooltip = "Click to switch CLJS build REPL"; + } else { + this.statusBarItem.text = "no build connected" + this.statusBarItem.tooltip = "Click to connect to a CLJS build REPL"; + } + } + + this.statusBarItem.text = text; + this.statusBarItem.tooltip = tooltip; + + if(this.statusBarItem.text) { + this.statusBarItem.show(); + } else { + this.statusBarItem.hide(); + } + } + + dispose() { + this.statusBarItem.dispose(); + } +} diff --git a/src/statusbar/connection.ts b/src/statusbar/connection.ts new file mode 100644 index 000000000..370b6287b --- /dev/null +++ b/src/statusbar/connection.ts @@ -0,0 +1,49 @@ +import { window, StatusBarAlignment, StatusBarItem } from "vscode"; +import configReader from "../configReader"; +import * as state from '../state'; +import * as util from '../utilities'; + +export class ConnectionStatusBarItem { + private statusBarItem: StatusBarItem; + + constructor(alignment: StatusBarAlignment) { + this.statusBarItem = window.createStatusBarItem(alignment); + } + + update() { + let current = state.deref(); + const colors = configReader.colors; + + let text = "nREPL $(zap)"; + let tooltip = "Click to jack-in or connect"; + let command = "calva.jackInOrConnect"; + let color = colors.disconnected; + + if (current.get('connected')) { + text = "nREPL $(zap)"; + color = colors.connected; + tooltip = `nrepl://${current.get('hostname')}:${current.get('port')} (Click to reset connection)`; + } else if (util.getLaunchingState()) { + color = colors.launching; + text = "Launching REPL using " + util.getLaunchingState(); + tooltip = "Click to interrupt jack-in or Connect to REPL Server"; + command = "calva.disconnect"; + } else if (util.getConnectingState()) { + color = colors.launching; + text = "nREPL - trying to connect"; + tooltip = "Click to interrupt jack-in or Connect to REPL Server"; + command = "calva.disconnect"; + } + + this.statusBarItem.text = text; + this.statusBarItem.tooltip = tooltip; + this.statusBarItem.command = command; + this.statusBarItem.color = color; + + this.statusBarItem.show(); + } + + dispose() { + this.statusBarItem.dispose(); + } +} diff --git a/src/statusbar/file-type.ts b/src/statusbar/file-type.ts new file mode 100644 index 000000000..e10c141f7 --- /dev/null +++ b/src/statusbar/file-type.ts @@ -0,0 +1,51 @@ +import { window, StatusBarAlignment, StatusBarItem } from "vscode"; +import { activeReplWindow } from '../repl-window'; +import configReader from "../configReader"; +import * as state from '../state'; +import * as util from '../utilities'; + +export class FileTypeStatusBarItem { + private statusBarItem: StatusBarItem; + constructor(alignment: StatusBarAlignment) { + this.statusBarItem = window.createStatusBarItem(alignment); + } + + update() { + const connected = state.deref().get("connected"); + const doc = util.getDocument({}); + const fileType = util.getFileType(doc); + const sessionType = util.getREPLSessionType(); + + let command = null; + let text = "Disconnected"; + let tooltip = "No active REPL session"; + let color = configReader.colors.disconnected; + + if(connected) { + if (fileType == 'cljc' && sessionType !== null && !activeReplWindow()) { + text = "cljc/" + sessionType; + if (util.getSession('clj') !== null && util.getSession('cljs') !== null) { + command = "calva.toggleCLJCSession"; + tooltip = `Click to use ${(sessionType === 'clj' ? 'cljs' : 'clj')} REPL for cljc`; + } + } else if (sessionType === 'cljs') { + text = "cljs"; + tooltip = "Connected to ClojureScript REPL"; + } else if (sessionType === 'clj') { + text = "clj"; + tooltip = "Connected to Clojure REPL"; + } + color = configReader.colors.typeStatus; + } + + this.statusBarItem.command = command; + this.statusBarItem.text = text; + this.statusBarItem.tooltip = tooltip; + this.statusBarItem.color = color + this.statusBarItem.show(); + } + + dispose() { + this.statusBarItem.dispose(); + } +} diff --git a/src/statusbar/index.ts b/src/statusbar/index.ts new file mode 100644 index 000000000..7df827f7e --- /dev/null +++ b/src/statusbar/index.ts @@ -0,0 +1,25 @@ +import { StatusBarAlignment } from "vscode"; +import { FileTypeStatusBarItem } from "./file-type"; +import { PrettyPrintStatusBarItem } from "./pretty-print"; +import { CljsBuildStatusBarItem } from "./cljs-build"; +import { ConnectionStatusBarItem } from "./connection"; + +const statusBarItems = []; + +function init(): any[] { + statusBarItems.push(new ConnectionStatusBarItem(StatusBarAlignment.Left)); + statusBarItems.push(new FileTypeStatusBarItem(StatusBarAlignment.Left)); + statusBarItems.push(new CljsBuildStatusBarItem(StatusBarAlignment.Left)); + statusBarItems.push(new PrettyPrintStatusBarItem(StatusBarAlignment.Right)); + update(); + return statusBarItems; +} + +function update() { + statusBarItems.forEach(sbi => sbi.update()); +} + +export default { + init, + update +} diff --git a/src/statusbar/pretty-print.ts b/src/statusbar/pretty-print.ts new file mode 100644 index 000000000..b076b8b26 --- /dev/null +++ b/src/statusbar/pretty-print.ts @@ -0,0 +1,25 @@ +import { window, StatusBarAlignment, StatusBarItem } from "vscode"; +import configReader from "../configReader"; +import * as state from '../state'; + +export class PrettyPrintStatusBarItem { + private statusBarItem: StatusBarItem; + constructor(alignment: StatusBarAlignment) { + this.statusBarItem = window.createStatusBarItem(alignment); + this.statusBarItem.command = "calva.togglePrettyPrint"; + this.statusBarItem.text = "pprint"; + } + + update() { + const color = configReader.colors; + const pprint = state.config().prettyPrintingOptions.enabled; + this.statusBarItem.tooltip = `Turn pretty printing ${pprint ? 'off' : 'on'}`; + this.statusBarItem.color = pprint ? color.active : color.inactive; + + this.statusBarItem.show(); + } + + dispose() { + this.statusBarItem.dispose(); + } +}