diff --git a/.vscode/launch.json b/.vscode/launch.json
index 6411a970..d80e5e7c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -14,6 +14,9 @@
"${workspaceFolder}/out/**/*.js"
],
"sourceMaps": true,
+ "cascadeTerminateToConfigurations": [
+ "Attach to TS Server",
+ ],
"env": {
"TSS_DEBUG": "9223",
"TSS_REMOTE_DEBUG": "9223"
@@ -25,6 +28,7 @@
"request": "attach",
"restart": true,
"port": 9223,
+ "customDescriptionGenerator": "function (def) { return this?.__debugKind || this?.__debugFlags || def }",
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*.js"
@@ -49,6 +53,13 @@
"Launch Extension",
"Attach to TS Server"
]
- }
+ },
+ {
+ "name": "Extension + Volar",
+ "configurations": [
+ "Launch Extension",
+ "Attach to Vue Semantic Server"
+ ]
+ },
]
}
diff --git a/README.MD b/README.MD
index d6dec33e..628863e3 100644
--- a/README.MD
+++ b/README.MD
@@ -16,7 +16,7 @@ TOC:
- [Contributed Code Actions](#contributed-code-actions)
- [Even Even More](#even-even-more)
-> *Note*: You can disable all optional features with `> Disable All Optional Features` setting right after install.
+> *Note*: You can disable all optional features with `> Disable All Optional Features` command right after install.
>
> *Note*: Visit website for list of recommended settings:
@@ -42,7 +42,7 @@ Also is not supported in the web.
90% work done in this extension highly improves completions experience!
-### Strict Emmet
+### Strict JSX Emmet
(*enabled by default*) when react langs are in `emmet.excludeLanguages`
diff --git a/package.json b/package.json
index 06d57dcb..eb74a4ce 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,10 @@
{
"command": "replaceGlobalTypescriptWithLocalVersion",
"title": "Replace Global Typescript with Local Version"
+ },
+ {
+ "command": "getArgumentReferencesFromCurrentParameter",
+ "title": "Get Argument References from Current Parameter"
}
],
"keybindings": [
@@ -201,4 +205,4 @@
"runTest": false
}
}
-}
\ No newline at end of file
+}
diff --git a/playground.ts b/playground.ts
index 484633a6..5a47d3ef 100644
--- a/playground.ts
+++ b/playground.ts
@@ -2,7 +2,13 @@
import ts from 'typescript/lib/tsserverlibrary'
import { createLanguageService } from './typescript/src/dummyLanguageService'
-let testString = 'const a: {/** @default test */a: 5} | {b: 6, /** yes */a: 9} = null as any;\nif ("||" in a) {}'
+globalThis.ts = ts
+
+let testString = /* ts */ `
+const b = () => 5
+const a = b()|| as
+new Promise()
+`
const replacement = '||'
const pos = testString.indexOf(replacement)
testString = testString.slice(0, pos) + testString.slice(pos + replacement.length)
@@ -16,7 +22,7 @@ const sourceFile = program?.getSourceFile(filePath)
if (!program || !sourceFile) throw new Error('No source file')
const typeChecker = program.getTypeChecker()
-const node = findChildContainingPosition(ts, sourceFile, pos)
+let node = findChildContainingPosition(ts, sourceFile, pos)
if (!node) throw new Error('No node')
const type = typeChecker.getTypeAtLocation(node)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d732cc0b..a62fb5b9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,4 +1,4 @@
-lockfileVersion: '6.1'
+lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@@ -715,7 +715,7 @@ packages:
dependencies:
'@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.4
- '@types/node': 16.11.21
+ '@types/node': 16.18.3
'@types/responselike': 1.0.0
dev: true
@@ -777,7 +777,7 @@ packages:
/@types/keyv@3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
- '@types/node': 16.11.21
+ '@types/node': 16.18.3
dev: true
/@types/lodash@4.14.182:
@@ -817,7 +817,7 @@ packages:
/@types/responselike@1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
- '@types/node': 16.11.21
+ '@types/node': 16.18.3
dev: true
/@types/semver@7.3.13:
@@ -3450,7 +3450,6 @@ packages:
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
- dev: false
/graceful-fs@4.2.9:
resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==}
@@ -3976,7 +3975,7 @@ packages:
dependencies:
universalify: 2.0.0
optionalDependencies:
- graceful-fs: 4.2.9
+ graceful-fs: 4.2.11
/jsonify@0.0.0:
resolution: {integrity: sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=}
diff --git a/src/apiCommands.ts b/src/apiCommands.ts
index 4ad98adf..a6523857 100644
--- a/src/apiCommands.ts
+++ b/src/apiCommands.ts
@@ -27,7 +27,7 @@ export const sharedApiRequest = async (type: TriggerCharacterCommand, { offset,
if (!position) offset ??= document.offsetAt(activeTextEditor!.selection.active) + relativeOffset
const requestOffset = offset ?? document.offsetAt(position!)
const requestPos = position ?? document.positionAt(offset!)
- const getData = async () => sendCommand(type, { document: document!, position: requestPos })
+ const getData = async () => sendCommand(type, { document: document!, position: requestPos, inputOptions: {} })
const CACHE_UNDEFINED_TIMEOUT = 1000
if (cacheableCommands.has(type as any)) {
const cacheEntry = operationsCache.get(type)
diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts
index 5942530b..be25dc1e 100644
--- a/src/codeActionProvider.ts
+++ b/src/codeActionProvider.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode'
import { defaultJsSupersetLangsWithVue } from '@zardoy/vscode-utils/build/langs'
import { registerExtensionCommand, showQuickPick, getExtensionSetting, getExtensionCommandId } from 'vscode-framework'
import { compact } from '@zardoy/utils'
-import { RequestResponseTypes, RequestOptionsTypes } from '../typescript/src/ipcTypes'
+import { RequestOutputTypes, RequestInputTypes } from '../typescript/src/ipcTypes'
import { sendCommand } from './sendCommand'
import { tsTextChangesToVscodeTextEdits, vscodeRangeToTs, tsTextChangesToVscodeSnippetTextEdits } from './util'
@@ -26,7 +26,7 @@ export default () => {
return
}
- const fixAllEdits = await sendCommand('getFixAllEdits', {
+ const fixAllEdits = await sendCommand('getFixAllEdits', {
document,
})
if (!fixAllEdits || token.isCancellationRequested) return
@@ -89,16 +89,13 @@ export default () => {
async resolveCodeAction(codeAction: ExtendedCodeAction, token) {
const { document } = codeAction
if (!document) throw new Error('Unresolved code action without document')
- const result = await sendCommand(
- 'getExtendedCodeActionEdits',
- {
- document,
- inputOptions: {
- applyCodeActionTitle: codeAction.title,
- range: vscodeRangeToTs(document, codeAction.diagnostics?.length ? codeAction.diagnostics[0]!.range : codeAction.requestRange),
- },
+ const result = await sendCommand('getExtendedCodeActionEdits', {
+ document,
+ inputOptions: {
+ applyCodeActionTitle: codeAction.title,
+ range: vscodeRangeToTs(document, codeAction.diagnostics?.length ? codeAction.diagnostics[0]!.range : codeAction.requestRange),
},
- )
+ })
if (!result) throw new Error('No code action edits. Try debug.')
const { edits = [], snippetEdits = [] } = result
const workspaceEdit = new vscode.WorkspaceEdit()
@@ -111,9 +108,9 @@ export default () => {
},
})
- registerExtensionCommand('applyRefactor' as any, async (_, arg?: RequestResponseTypes['getTwoStepCodeActions']) => {
+ registerExtensionCommand('applyRefactor' as any, async (_, arg?: RequestOutputTypes['getTwoStepCodeActions']) => {
if (!arg) return
- let sendNextData: RequestOptionsTypes['twoStepCodeActionSecondStep']['data'] | undefined
+ let sendNextData: RequestInputTypes['twoStepCodeActionSecondStep']['data'] | undefined
const { turnArrayIntoObject } = arg
if (turnArrayIntoObject) {
const { keysCount, totalCount, totalObjectCount } = turnArrayIntoObject
@@ -151,7 +148,7 @@ export default () => {
})
async function getPossibleTwoStepRefactorings(range: vscode.Range, document = vscode.window.activeTextEditor!.document) {
- return sendCommand('getTwoStepCodeActions', {
+ return sendCommand('getTwoStepCodeActions', {
document,
position: range.start,
inputOptions: {
@@ -161,16 +158,13 @@ export default () => {
}
async function getSecondStepRefactoringData(range: vscode.Range, secondStepData?: any, document = vscode.window.activeTextEditor!.document) {
- return sendCommand(
- 'twoStepCodeActionSecondStep',
- {
- document,
- position: range.start,
- inputOptions: {
- range: vscodeRangeToTs(document, range),
- data: secondStepData,
- },
+ return sendCommand('twoStepCodeActionSecondStep', {
+ document,
+ position: range.start,
+ inputOptions: {
+ range: vscodeRangeToTs(document, range),
+ data: secondStepData,
},
- )
+ })
}
}
diff --git a/src/emmet.ts b/src/emmet.ts
index da6b8bc3..1c2dd3ce 100644
--- a/src/emmet.ts
+++ b/src/emmet.ts
@@ -1,7 +1,6 @@
import * as vscode from 'vscode'
import { compact } from '@zardoy/utils'
import { getExtensionSetting, registerExtensionCommand } from 'vscode-framework'
-import { EmmetResult } from '../typescript/src/ipcTypes'
import { sendCommand } from './sendCommand'
import { Configuration } from './configurationType'
@@ -29,7 +28,7 @@ export const registerEmmet = async () => {
const cursorOffset: number = document.offsetAt(position)
if (context.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions || !lastStartOffset) {
- const result = await sendCommand('emmet-completions', { document, position })
+ const result = await sendCommand('emmet-completions', { document, position })
if (!result) {
lastStartOffset = undefined
return
diff --git a/src/extension.ts b/src/extension.ts
index b002aed3..8f037d37 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,10 +1,9 @@
/* eslint-disable @typescript-eslint/no-require-imports */
import * as vscode from 'vscode'
import { defaultJsSupersetLangs } from '@zardoy/vscode-utils/build/langs'
-import { Settings, extensionCtx, getExtensionSetting, getExtensionSettingId, registerExtensionCommand } from 'vscode-framework'
+import { extensionCtx, getExtensionSetting, getExtensionSettingId } from 'vscode-framework'
import { pickObj } from '@zardoy/utils'
import { watchExtensionSettings } from '@zardoy/vscode-utils/build/settings'
-import { ConditionalPick } from 'type-fest'
import webImports from './webImports'
import { sendCommand } from './sendCommand'
import { registerEmmet } from './emmet'
@@ -27,13 +26,21 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted
isActivated = true
let webWaitingForConfigSync = false
+ const getResolvedConfig = () => {
+ const configuration = vscode.workspace.getConfiguration()
+ const config: any = {
+ ...configuration.get(process.env.IDS_PREFIX!),
+ editorSuggestInsertModeReplace: configuration.get('editor.suggest.insertMode') === 'replace',
+ }
+ mergeSettingsFromScopes(config, 'typescript', extensionCtx.extension.packageJSON)
+ return config
+ }
+
const syncConfig = () => {
if (!tsApi) return
console.log('sending configure request for typescript-essential-plugins')
- const config: any = { ...vscode.workspace.getConfiguration().get(process.env.IDS_PREFIX!) }
// todo implement language-specific settings
- mergeSettingsFromScopes(config, 'typescript', extensionCtx.extension.packageJSON)
-
+ const config = getResolvedConfig()
tsApi.configurePlugin('typescript-essential-plugins', config)
if (process.env.PLATFORM === 'node') {
@@ -50,7 +57,7 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted
}
vscode.workspace.onDidChangeConfiguration(async ({ affectsConfiguration }) => {
- if (affectsConfiguration(process.env.IDS_PREFIX!)) {
+ if (affectsConfiguration(process.env.IDS_PREFIX!) || affectsConfiguration('editor.suggest.insertMode')) {
syncConfig()
if (
process.env.PLATFORM === 'node' &&
@@ -72,8 +79,8 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted
if (!activeTextEditor || !vscode.languages.match(defaultJsSupersetLangs, activeTextEditor.document)) return
if (!webWaitingForConfigSync) return
// webWaitingForConfigSync = false
- const config = vscode.workspace.getConfiguration().get(process.env.IDS_PREFIX!)
- void sendCommand(`updateConfig${JSON.stringify(config)}` as any)
+ const config = getResolvedConfig()
+ void sendCommand(`updateConfig${JSON.stringify(config)}` as any, { inputOptions: {} })
}
vscode.window.onDidChangeActiveTextEditor(possiblySyncConfig)
diff --git a/src/onCompletionAccepted.ts b/src/onCompletionAccepted.ts
index c29c9e80..1f77d039 100644
--- a/src/onCompletionAccepted.ts
+++ b/src/onCompletionAccepted.ts
@@ -62,33 +62,37 @@ export default (tsApi: { onCompletionAccepted }) => {
const nextChar = editor.document.getText(new vscode.Range(startPos, startPos.translate(0, 1)))
if (!params || ['(', '.', '`'].includes(nextChar)) return
- if (isAmbiguous && lastAcceptedAmbiguousMethodSnippetSuggestion !== suggestionName) {
- lastAcceptedAmbiguousMethodSnippetSuggestion = suggestionName
- return
- }
+ if (getExtensionSetting('methodSnippetsInsertText') === 'disable') {
+ // handle insertion only if it wasn't handled by methodSnippetsInsertText already
+ if (isAmbiguous && lastAcceptedAmbiguousMethodSnippetSuggestion !== suggestionName) {
+ lastAcceptedAmbiguousMethodSnippetSuggestion = suggestionName
+ return
+ }
- const replaceArguments = getExtensionSetting('methodSnippets.replaceArguments')
-
- const snippet = new vscode.SnippetString('')
- snippet.appendText('(')
- // todo maybe when have optional (skipped), add a way to leave trailing , with tabstop (previous behavior)
- for (const [i, param] of params.entries()) {
- const replacer = replaceArguments[param.replace(/\?$/, '')]
- if (replacer === null) continue
- if (replacer) {
- useReplacer(snippet, replacer)
- } else {
- snippet.appendPlaceholder(param)
+ const replaceArguments = getExtensionSetting('methodSnippets.replaceArguments')
+
+ const snippet = new vscode.SnippetString('')
+ snippet.appendText('(')
+ // todo maybe when have optional (skipped), add a way to leave trailing , with tabstop (previous behavior)
+ for (const [i, param] of params.entries()) {
+ const replacer = replaceArguments[param.replace(/\?$/, '')]
+ if (replacer === null) continue
+ if (replacer) {
+ useReplacer(snippet, replacer)
+ } else {
+ snippet.appendPlaceholder(param)
+ }
+
+ if (i !== params.length - 1) snippet.appendText(', ')
}
- if (i !== params.length - 1) snippet.appendText(', ')
+ snippet.appendText(')')
+ void editor.insertSnippet(snippet, undefined, {
+ undoStopAfter: false,
+ undoStopBefore: false,
+ })
}
- snippet.appendText(')')
- void editor.insertSnippet(snippet, undefined, {
- undoStopAfter: false,
- undoStopBefore: false,
- })
if (vscode.workspace.getConfiguration('editor.parameterHints').get('enabled') && params.length > 0) {
void vscode.commands.executeCommand('editor.action.triggerParameterHints')
}
diff --git a/src/sendCommand.ts b/src/sendCommand.ts
index 518bb88f..4c17a49a 100644
--- a/src/sendCommand.ts
+++ b/src/sendCommand.ts
@@ -1,17 +1,22 @@
import * as vscode from 'vscode'
import { getActiveRegularEditor } from '@zardoy/vscode-utils'
import { getExtensionSetting } from 'vscode-framework'
-import { passthroughExposedApiCommands, TriggerCharacterCommand } from '../typescript/src/ipcTypes'
+import { passthroughExposedApiCommands, TriggerCharacterCommand, RequestInputTypes, RequestOutputTypes } from '../typescript/src/ipcTypes'
-type SendCommandData = {
+type SendCommandData = {
position?: vscode.Position
document?: vscode.TextDocument
- inputOptions?: K
-}
-export const sendCommand = async (
- command: TriggerCharacterCommand,
- sendCommandDataArg?: SendCommandData,
-): Promise => {
+ // eslint-disable-next-line @typescript-eslint/ban-types
+} & ([Input] extends [never] ? {} : { inputOptions: Input })
+
+export const sendCommand = async <
+ Command extends TriggerCharacterCommand,
+ Input = RequestInputTypes[Command & keyof RequestInputTypes],
+ Output = RequestOutputTypes[Command & keyof RequestOutputTypes] extends never ? any : RequestOutputTypes[Command & keyof RequestOutputTypes],
+>(
+ command: Command,
+ sendCommandDataArg: SendCommandData,
+): Promise