tailwind-ctp-intellisense/src/lsp/server.ts

207 lines
6.0 KiB
TypeScript
Raw Normal View History

2020-04-11 21:20:45 +00:00
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import {
createConnection,
TextDocuments,
ProposedFeatures,
TextDocumentSyncKind,
CompletionItem,
InitializeParams,
InitializeResult,
CompletionParams,
CompletionList,
2020-04-12 14:48:38 +00:00
Hover,
TextDocumentPositionParams,
2020-04-16 21:39:16 +00:00
DidChangeConfigurationNotification,
2020-04-11 21:20:45 +00:00
} from 'vscode-languageserver'
2020-05-03 14:57:15 +00:00
import getTailwindState from '../class-names/index'
2020-04-22 19:29:36 +00:00
import { State, Settings, EditorState } from './util/state'
2020-04-11 21:20:45 +00:00
import {
provideCompletions,
resolveCompletionItem,
} from './providers/completionProvider'
2020-04-12 14:48:38 +00:00
import { provideHover } from './providers/hoverProvider'
2020-04-11 21:20:45 +00:00
import { URI } from 'vscode-uri'
2020-04-16 21:39:16 +00:00
import { getDocumentSettings } from './util/getDocumentSettings'
2020-05-09 21:11:35 +00:00
import { provideDiagnostics } from './providers/diagnosticsProvider'
2020-04-11 21:20:45 +00:00
2020-04-22 19:29:36 +00:00
let state: State = { enabled: false }
2020-04-11 21:20:45 +00:00
let connection = createConnection(ProposedFeatures.all)
let documents = new TextDocuments()
let workspaceFolder: string | null
const defaultSettings: Settings = {
emmetCompletions: false,
includeLanguages: {},
validate: true,
lint: {
utilityConflicts: 'warning',
unsupportedApply: 'error',
},
}
2020-04-16 21:39:16 +00:00
let globalSettings: Settings = defaultSettings
let documentSettings: Map<string, Settings> = new Map()
2020-04-11 21:20:45 +00:00
documents.onDidOpen((event) => {
2020-04-16 21:39:16 +00:00
getDocumentSettings(state, event.document.uri)
})
documents.onDidClose((event) => {
documentSettings.delete(event.document.uri)
2020-04-11 21:20:45 +00:00
})
2020-05-09 21:11:35 +00:00
documents.onDidChangeContent((change) => {
provideDiagnostics(state, change.document)
})
2020-04-11 21:20:45 +00:00
documents.listen(connection)
connection.onInitialize(
async (params: InitializeParams): Promise<InitializeResult> => {
2020-04-22 19:29:36 +00:00
const capabilities = params.capabilities
const editorState: EditorState = {
connection,
documents,
documentSettings,
globalSettings,
userLanguages:
params.initializationOptions &&
params.initializationOptions.userLanguages
? params.initializationOptions.userLanguages
: {},
2020-04-22 19:29:36 +00:00
capabilities: {
configuration:
capabilities.workspace && !!capabilities.workspace.configuration,
2020-05-09 21:11:35 +00:00
diagnosticRelatedInformation:
capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics &&
capabilities.textDocument.publishDiagnostics.relatedInformation,
2020-04-22 19:29:36 +00:00
},
}
const tailwindState = await getTailwindState(
2020-04-11 21:20:45 +00:00
params.rootPath || URI.parse(params.rootUri).path,
{
2020-05-03 14:57:15 +00:00
// @ts-ignore
2020-04-11 21:20:45 +00:00
onChange: (newState: State): void => {
2020-04-23 18:54:01 +00:00
if (newState && !newState.error) {
2020-04-22 19:29:36 +00:00
state = { ...newState, enabled: true, editor: editorState }
connection.sendNotification('tailwindcss/configUpdated', [
state.configPath,
state.config,
state.plugins,
])
} else {
state = { enabled: false, editor: editorState }
2020-04-23 18:54:01 +00:00
if (newState && newState.error) {
const payload: {
message: string
file?: string
line?: number
} = { message: newState.error.message }
const lines = newState.error.stack.toString().split('\n')
const match = /^(?<file>.*?):(?<line>[0-9]+)$/.exec(lines[0])
if (match) {
payload.file = match.groups.file
payload.line = parseInt(match.groups.line, 10)
}
connection.sendNotification('tailwindcss/configError', [payload])
}
2020-04-22 19:29:36 +00:00
// TODO
// connection.sendNotification('tailwindcss/configUpdated', [null])
}
2020-04-11 21:20:45 +00:00
},
}
)
2020-04-16 21:39:16 +00:00
2020-04-22 19:29:36 +00:00
if (tailwindState) {
state = { enabled: true, editor: editorState, ...tailwindState }
} else {
state = { enabled: false, editor: editorState }
2020-04-16 21:39:16 +00:00
}
2020-04-11 21:20:45 +00:00
return {
capabilities: {
// textDocumentSync: {
// openClose: true,
// change: TextDocumentSyncKind.None
// },
textDocumentSync: documents.syncKind,
completionProvider: {
resolveProvider: true,
2020-04-22 19:29:36 +00:00
triggerCharacters: [
// class attributes
'"',
"'",
'`',
// between class names
' ',
// @apply and emmet-style
'.',
// config/theme helper
'[',
// TODO: restart server if separater changes?
typeof state.separator === 'undefined' ? ':' : state.separator,
],
2020-04-11 21:20:45 +00:00
},
2020-04-12 14:48:38 +00:00
hoverProvider: true,
2020-04-11 21:20:45 +00:00
},
}
}
)
connection.onInitialized &&
connection.onInitialized(async () => {
2020-04-16 21:39:16 +00:00
if (state.editor.capabilities.configuration) {
connection.client.register(
DidChangeConfigurationNotification.type,
undefined
)
}
2020-04-11 21:20:45 +00:00
connection.sendNotification('tailwindcss/configUpdated', [
2020-04-22 19:29:36 +00:00
state.configPath,
2020-04-11 21:20:45 +00:00
state.config,
state.plugins,
])
})
2020-04-16 21:39:16 +00:00
connection.onDidChangeConfiguration((change) => {
if (state.editor.capabilities.configuration) {
// Reset all cached document settings
state.editor.documentSettings.clear()
} else {
state.editor.globalSettings = <Settings>(
(change.settings.tailwindCSS || defaultSettings)
)
}
state.editor.documents.all().forEach((doc) => {
provideDiagnostics(state, doc)
})
2020-04-16 21:39:16 +00:00
})
2020-04-11 21:20:45 +00:00
connection.onCompletion(
2020-04-16 21:39:16 +00:00
(params: CompletionParams): Promise<CompletionList> => {
2020-04-22 19:29:36 +00:00
if (!state.enabled) return null
2020-04-11 21:20:45 +00:00
return provideCompletions(state, params)
}
)
connection.onCompletionResolve(
(item: CompletionItem): CompletionItem => {
2020-04-22 19:29:36 +00:00
if (!state.enabled) return null
2020-04-11 21:20:45 +00:00
return resolveCompletionItem(state, item)
}
)
2020-04-12 14:48:38 +00:00
connection.onHover(
(params: TextDocumentPositionParams): Hover => {
2020-04-22 19:29:36 +00:00
if (!state.enabled) return null
2020-04-12 14:48:38 +00:00
return provideHover(state, params)
}
)
2020-04-11 21:20:45 +00:00
connection.listen()