Skip to content

Commit

Permalink
Epic - Dynamic diagram on LSP IDE (#99)
Browse files Browse the repository at this point in the history
* repl: avoid erroring if no Wollok file is selected

* Add configuration for REPL / dynamic diagram

* Fix #101 - warn if wollok-cli path is not set

* Fix #98 - kill all terminals when running REPL

* Fix #101 - Fix tests

* Add dark mode configuration

* Fix tests for dark mode
  • Loading branch information
fdodino authored Oct 2, 2023
1 parent cd6eb0c commit 5f9e321
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 66 deletions.
43 changes: 29 additions & 14 deletions client/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,34 @@ export const runAllTests = (): Task =>
'--skipValidations',
])

export const startRepl = (): Task => {
const currentDocument = window.activeTextEditor.document
const currentFileName = path.basename(currentDocument.uri.path)
const getCurrentFileName = (document: vscode.TextDocument | undefined) =>
document ? path.basename(document.uri.path) : 'Synthetic File'

const replTask = wollokCLITask('repl', `Wollok Repl: ${currentFileName}`, [
'repl',
fsToShell(currentDocument.uri.fsPath),
'--skipValidations',
])
const getFiles = (document: vscode.TextDocument | undefined) =>
document ? [fsToShell(document.uri.fsPath)] : []

setTimeout(() => {
vscode.commands.executeCommand('simpleBrowser.show', 'http://localhost:3000/')
}, 1000)
const DYNAMIC_DIAGRAM_URI = 'http://localhost:3000/'

export const startRepl = (): Task => {
const currentDocument = window.activeTextEditor?.document
const wollokLSPConfiguration = workspace.getConfiguration('wollokLSP')
const dynamicDiagramDarkMode = wollokLSPConfiguration.get('dynamicDiagramDarkMode') ?? false
const cliCommands = [`repl`, ...getFiles(currentDocument), '--skipValidations', dynamicDiagramDarkMode ? '--darkMode' : '']
// Terminate previous tasks
vscode.commands.executeCommand('workbench.action.terminal.killAll')
const replTask = wollokCLITask('repl', `Wollok Repl: ${getCurrentFileName(currentDocument)}`, cliCommands)

const openDynamicDiagram = wollokLSPConfiguration.get('openDynamicDiagramOnRepl') as boolean
if (openDynamicDiagram) {
setTimeout(() => {
const openInternalDynamicDiagram = wollokLSPConfiguration.get('openInternalDynamicDiagram') as boolean
if (openInternalDynamicDiagram) {
vscode.commands.executeCommand('simpleBrowser.show', DYNAMIC_DIAGRAM_URI)
} else {
vscode.env.openExternal(vscode.Uri.parse(DYNAMIC_DIAGRAM_URI))
}
}, 1000)
}
return replTask
}

Expand All @@ -80,9 +94,10 @@ const registerCLICommand = (
)

const wollokCLITask = (task: string, name: string, cliCommands: string[]) => {
const wollokCli = unknownToShell(
workspace.getConfiguration('wollokLinter').get('cli-path'),
)
const wollokCliPath: string = workspace.getConfiguration('wollokLSP').get('cli-path')
// TODO: i18n - but it's in the server
if (!wollokCliPath) throw new Error('Missing configuration WollokLSP/cli-path in order to run Wollok tasks')
const wollokCli = unknownToShell(wollokCliPath)
const folder = workspace.workspaceFolders[0]
const shellCommand = [
wollokCli,
Expand Down
15 changes: 13 additions & 2 deletions client/src/test/commands.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import * as assert from 'assert'
import * as sinon from 'sinon'
import { ShellExecution, Task, Uri, env } from 'vscode'
import { ShellExecution, Task, Uri, env, workspace } from 'vscode'
import { runAllTests, runProgram, runTests, startRepl } from '../commands'
import { activate, getDocumentURI, getFolderURI } from './helper'
import { toPosix, toWin, Shell } from '../platform-string-utils'
import { afterEach, beforeEach } from 'mocha'

suite('Should run commands', () => {
const folderURI = getFolderURI()
const pepitaURI = getDocumentURI('pepita.wlk')

beforeEach(() => {
sinon.stub(workspace, 'getConfiguration').value((_configuration: string) => ({
get: (_value: string) => '/usr/bin/wollok-ts-cli',
}))
})

afterEach(() => {
sinon.restore()
})

test('run program', async () => {
await onWindowsBash(() =>
testCommand(
Expand Down Expand Up @@ -71,7 +82,7 @@ suite('Should run commands', () => {
startRepl,
` repl ${toPosix(
pepitaURI.fsPath,
)} --skipValidations -p ${expectedPathByShell(
)} --skipValidations --darkMode -p ${expectedPathByShell(
'bash',
folderURI.fsPath,
)}`,
Expand Down
51 changes: 38 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,13 @@
"type": "object",
"title": "Wollok LSP IDE",
"properties": {
"wollokLinter.cli-path": {
"wollokLSP.cli-path": {
"scope": "resource",
"type": "string",
"description": "Path to Wollok-CLI."
"description": "Path to Wollok-CLI.",
"order": 0
},
"wollokLinter.maxNumberOfProblems": {
"scope": "resource",
"type": "number",
"default": 100,
"description": "Controls the maximum number of problems produced by the server."
},
"wollokLinter.language": {
"wollokLSP.language": {
"scope": "resource",
"type": "string",
"enum": [
Expand All @@ -76,9 +71,17 @@
"Based on Local Environment"
],
"default": "Based on Local Environment",
"description": "Language used while reporting linter errors and warnings."
"description": "Language used while reporting linter errors and warnings.",
"order": 1
},
"wollokLSP.maxNumberOfProblems": {
"scope": "resource",
"type": "number",
"default": 100,
"description": "Controls the maximum number of problems produced by the server.",
"order": 2
},
"wollokLinter.trace.server": {
"wollokLSP.trace.server": {
"scope": "window",
"type": "string",
"enum": [
Expand All @@ -87,15 +90,37 @@
"verbose"
],
"default": "off",
"description": "Traces the communication between VS Code and the language server."
"description": "Traces the communication between VS Code and the language server.",
"order": 3
},
"wollokLSP.openDynamicDiagramOnRepl": {
"scope": "resource",
"type": "boolean",
"default": true,
"description": "Opens the dynamic diagram when running the REPL.",
"order": 4
},
"wollokLSP.openInternalDynamicDiagram": {
"scope": "resource",
"type": "boolean",
"default": true,
"description": "If true, opens an internal dynamic diagram inside Wollok IDE. If false, it will open a new external browser.",
"order": 5
},
"wollokLSP.dynamicDiagramDarkMode": {
"scope": "resource",
"type": "boolean",
"default": true,
"description": "If true, opens dynamic diagram in Dark Mode. Otherwise, it uses Light Mode.",
"order": 6
}
}
},
"commands": [
{
"command": "wollok.start.repl",
"title": "Start a new REPL session",
"category": "Wollok"
"category": "Wollok"
},
{
"command": "wollok.run.allTests",
Expand Down
40 changes: 28 additions & 12 deletions server/src/functionalities/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { lang } from '../settings'
// VALIDATION MESSAGES DEFINITION
// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════

type ValidationMessage = { [key: string]: string }
type Message = { [key: string]: string }

const FAILURE = 'failure'

const validationMessagesEn: ValidationMessage = {
const validationMessagesEn: Message = {
nameShouldBeginWithLowercase: 'The name {0} must start with lowercase',
nameShouldBeginWithUppercase: 'The name {0} must start with uppercase',
nameShouldNotBeKeyword:
Expand Down Expand Up @@ -95,7 +95,7 @@ const validationMessagesEn: ValidationMessage = {
[FAILURE]: 'Rule failure: ',
}

const validationMessagesEs: ValidationMessage = {
const validationMessagesEs: Message = {
nameShouldBeginWithLowercase:
'El nombre {0} debe comenzar con min\u00FAsculas',
nameShouldBeginWithUppercase:
Expand Down Expand Up @@ -195,9 +195,25 @@ const validationMessagesEs: ValidationMessage = {
[FAILURE]: 'La siguiente regla fall\u00F3: ',
}

const validationMessages: { [key: string]: ValidationMessage } = {
en: validationMessagesEn,
es: validationMessagesEs,
const MISSING_WOLLOK_TS_CLI = 'missing_wollok_ts_cli'

const lspMessagesEn = {
[MISSING_WOLLOK_TS_CLI]: 'Missing configuration WollokLSP/cli-pat in order to run Wollok tasks',
}

const lspMessagesEs = {
[MISSING_WOLLOK_TS_CLI]: 'Falta la configuración WollokLSP/cli-path para poder ejecutar tareas de Wollok',
}

const messages: { [key: string]: Message } = {
en: {
...validationMessagesEn,
...lspMessagesEn,
},
es: {
...validationMessagesEs,
...lspMessagesEs,
},
}

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -225,14 +241,14 @@ const interpolateValidationMessage = (message: string, ...values: string[]) =>
return values[index] || ''
})

const getBasicMessage = (problem: Problem) =>
validationI18nized()[problem.code] || convertToHumanReadable(problem.code)

const validationI18nized = () => validationMessages[lang()] as ValidationMessage
const validationI18nized = () => messages[lang()] as Message

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// PUBLIC INTERFACE
// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════

export const reportMessage = (problem: Problem): string =>
interpolateValidationMessage(getBasicMessage(problem), ...problem.values)
export const reportValidationMessage = (problem: Problem): string =>
getMessage(problem.code, problem.values.concat())

export const getMessage = (message: string, values: string[]): string =>
interpolateValidationMessage(validationI18nized()[message] || convertToHumanReadable(message), ...values)
4 changes: 2 additions & 2 deletions server/src/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
getTestCodeLenses,
} from './functionalities/code-lens'
import { getNodeDefinition } from './functionalities/definition'
import { reportMessage } from './functionalities/reporter'
import { reportValidationMessage } from './functionalities/reporter'
import { updateDocumentSettings } from './settings'
import {
documentSymbolsFor,
Expand Down Expand Up @@ -60,7 +60,7 @@ const createDiagnostic = (textDocument: TextDocument, problem: Problem) => {
severity: buildSeverity(problem),
range: trimIn(range, textDocument),
code: problem.code,
message: reportMessage(problem),
message: reportValidationMessage(problem),
source: '',
} as Diagnostic
}
Expand Down
19 changes: 2 additions & 17 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
validateTextDocument,
workspaceSymbols,
} from './linter'
import { initializeSettings, WollokLinterSettings } from './settings'
import { initializeSettings, WollokLSPSettings } from './settings'
import { templates } from './functionalities/autocomplete/templates'
import { EnvironmentProvider } from './utils/vm/environment-provider'

Expand Down Expand Up @@ -77,28 +77,13 @@ connection.onInitialized(() => {
})

// Cache the settings of all open documents
const documentSettings: Map<string, Thenable<WollokLinterSettings>> = new Map()
const documentSettings: Map<string, Thenable<WollokLSPSettings>> = new Map()

connection.onDidChangeConfiguration(() => {
// Revalidate all open text documents
documents.all().forEach(validateTextDocument(connection, documents.all()))
})

// function getDocumentSettings(resource: string): Thenable<ExampleSettings> {
// if (!hasConfigurationCapability) {
// return Promise.resolve(globalSettings)
// }
// let result = documentSettings.get(resource)
// if (!result) {
// result = connection.workspace.getConfiguration({
// scopeUri: resource,
// section: 'languageServerExample',
// })
// documentSettings.set(resource, result)
// }
// return result
// }

// Only keep settings for open documents
documents.onDidClose((e) => {
documentSettings.delete(e.document.uri)
Expand Down
18 changes: 12 additions & 6 deletions server/src/settings.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Connection } from 'vscode-languageserver/node'

export interface WollokLinterSettings {
export interface WollokLSPSettings {
maxNumberOfProblems: number
language: string
language: string,
openDynamicDiagramOnRepl: boolean,
openInternalDynamicDiagram: boolean,
dynamicDiagramDarkMode: boolean,
}

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Expand All @@ -18,12 +21,15 @@ const envLang = () => {
return fullLanguage ? fullLanguage.substring(0, 2) : SPANISH
}

const defaultSettings: WollokLinterSettings = {
const defaultSettings: WollokLSPSettings = {
maxNumberOfProblems: 1000,
language: envLang(),
openDynamicDiagramOnRepl: true,
openInternalDynamicDiagram: true,
dynamicDiagramDarkMode: true,
}

let globalSettings: WollokLinterSettings = defaultSettings
let globalSettings: WollokLSPSettings = defaultSettings

const languageDescription: { [key: string]: string } = {
Spanish: SPANISH,
Expand All @@ -38,8 +44,8 @@ export const updateDocumentSettings = async (
): Promise<void> => {
globalSettings =
((await connection.workspace.getConfiguration({
section: 'wollokLinter',
})) as WollokLinterSettings) || defaultSettings
section: 'wollokLSP',
})) as WollokLSPSettings) || defaultSettings
}

export const initializeSettings = async (
Expand Down

0 comments on commit 5f9e321

Please sign in to comment.