From bee660903d78b326896dbfbe7c72e12824bc7820 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Mon, 25 Mar 2024 09:55:50 +0000 Subject: [PATCH 1/3] starcoder was the original --- README.md | 2 +- src/common/constants.ts | 2 +- src/extension/fim-templates.ts | 13 ++++++++++--- src/extension/providers/completion.ts | 1 - 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f89f4d76..1ccfc4fd 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ For FIM completions, you need to use LLM models called "base models". Unlike ins If using Llama the model must support the Llama special tokens. - For computers with a good GPU, use: `deepseek-coder:base` or `codellama-code` (or any other good model that is optimised for code completions). -- For slower computers or computers using only CPU, use `stable-code:3b-code-q4_0` (or any other small base model). +- For slower computers or computers using only CPU, use `deepseek-coder:1.3b-base-q4_1` (or any other small base model). ## Keyboard shortcuts diff --git a/src/common/constants.ts b/src/common/constants.ts index 9fb3b8d9..5a1117b3 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -98,7 +98,7 @@ export const STOP_DEEPSEEK = [ '<|end▁of▁sentence|>' ] -export const STOP_STABLECODE = ['<|endoftext|>'] +export const STOP_STARCODER = ['<|endoftext|>'] export const API_PROVIDER: ApiProviders = { ollama: { diff --git a/src/extension/fim-templates.ts b/src/extension/fim-templates.ts index 56e53f0c..0550e8e7 100644 --- a/src/extension/fim-templates.ts +++ b/src/extension/fim-templates.ts @@ -2,7 +2,7 @@ import { FIM_TEMPLATE_FORMAT, STOP_DEEPSEEK, STOP_LLAMA, - STOP_STABLECODE + STOP_STARCODER } from '../common/constants' import { supportedLanguages } from '../common/languages' import { FimPromptTemplate } from '../common/types' @@ -104,7 +104,10 @@ function getFimTemplateChosen(format: string, args: FimPromptTemplate) { return getFimPromptTemplateDeepseek(args) } - if (format === FIM_TEMPLATE_FORMAT.stableCode || format === FIM_TEMPLATE_FORMAT.starcoder) { + if ( + format === FIM_TEMPLATE_FORMAT.stableCode || + format === FIM_TEMPLATE_FORMAT.starcoder + ) { return getFimPromptTemplateStableCode(args) } @@ -147,7 +150,11 @@ export const getStopWordsAuto = (fimModel: string) => { export const getStopWordsChosen = (format: string) => { if (format === FIM_TEMPLATE_FORMAT.codellama) return STOP_LLAMA if (format === FIM_TEMPLATE_FORMAT.deepseek) return STOP_DEEPSEEK - if (format === FIM_TEMPLATE_FORMAT.stableCode || format === FIM_TEMPLATE_FORMAT.starcoder) return STOP_STABLECODE + if ( + format === FIM_TEMPLATE_FORMAT.stableCode || + format === FIM_TEMPLATE_FORMAT.starcoder + ) + return STOP_STARCODER return STOP_LLAMA } diff --git a/src/extension/providers/completion.ts b/src/extension/providers/completion.ts index 9561e03b..547c92f9 100644 --- a/src/extension/providers/completion.ts +++ b/src/extension/providers/completion.ts @@ -134,7 +134,6 @@ export class CompletionProvider implements InlineCompletionItemProvider { position ) - if ( getIsMiddleOfWord() || isLastCompletionAccepted || From ee304cc17e38ba20d5e12355def623be4519e582 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Mon, 25 Mar 2024 19:56:44 +0000 Subject: [PATCH 2/3] inline completion fixes --- src/common/constants.ts | 1 + src/extension/completion-formatter.ts | 3 +- src/extension/parser-utils.ts | 5 +- src/extension/providers/completion.ts | 16 ++--- src/extension/utils.ts | 90 ++++++++++----------------- 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/src/common/constants.ts b/src/common/constants.ts index 5a1117b3..98a32d3a 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -211,6 +211,7 @@ export const MULTI_LINE_NODE_TYPE = [ 'object_type', 'interface_body', 'class_body', + 'export_statement', // react 'jsx_opening_element', 'jsx_self_closing_element', diff --git a/src/extension/completion-formatter.ts b/src/extension/completion-formatter.ts index 307c2b36..cd1fb3fc 100644 --- a/src/extension/completion-formatter.ts +++ b/src/extension/completion-formatter.ts @@ -2,7 +2,7 @@ import { Position, Range, TextEditor } from 'vscode' import { CLOSING_BRACKETS, OPENING_BRACKETS, QUOTES } from '../common/constants' import { Bracket } from '../common/types' -import { getNoTextBeforeOrAfter } from './utils' +import { getIsOnlyBrackets, getNoTextBeforeOrAfter } from './utils' export class CompletionFormatter { private _characterAfterCursor: string @@ -170,6 +170,7 @@ export class CompletionFormatter { private preventDuplicateLines = (): CompletionFormatter => { const lineCount = this._editor.document.lineCount let nextLineIndex = this._cursorPosition.line + 1 + if (getIsOnlyBrackets(this._normalisedCompletion)) return this while ( nextLineIndex < this._cursorPosition.line + 3 && nextLineIndex < lineCount diff --git a/src/extension/parser-utils.ts b/src/extension/parser-utils.ts index aa0d57c4..d015e870 100644 --- a/src/extension/parser-utils.ts +++ b/src/extension/parser-utils.ts @@ -101,7 +101,10 @@ export const getIsEmptyMultiLineBlock = (node: SyntaxNode | null): boolean => { const isOnlyBrackets = getIsOnlyBrackets( node.children.map((n) => n.text).join('') ) - return isMultiLineType && (isOnlyBrackets || !node.hasError) + return ( + (isMultiLineType && (isOnlyBrackets || !node.hasError)) || + node.type === 'export_statement' + ) } export const getOpenAndCloseBracketMatchJsx = (node: SyntaxNode | null) => { diff --git a/src/extension/providers/completion.ts b/src/extension/providers/completion.ts index 547c92f9..ad4a5c06 100644 --- a/src/extension/providers/completion.ts +++ b/src/extension/providers/completion.ts @@ -17,8 +17,8 @@ import { getFimDataFromProvider, getPrefixSuffix, getShouldSkipCompletion, - isCursorInEmptyString, - isMiddleWord as getIsMiddleOfWord + getIsMultiLineCompletion, + getIsMiddleWord } from '../utils' import { cache } from '../cache' import { supportedLanguages } from '../../common/languages' @@ -43,7 +43,7 @@ import Parser, { SyntaxNode } from 'web-tree-sitter' import { getIsMultiLineCompletionNode, getNodeAtPosition, - getParserForFile, + getParserForFile } from '../parser-utils' export class CompletionProvider implements InlineCompletionItemProvider { @@ -110,12 +110,12 @@ export class CompletionProvider implements InlineCompletionItemProvider { this._parser = await getParserForFile(this._document.uri.fsPath) const tree = this._parser?.parse(this._document.getText()) this._currentNode = getNodeAtPosition(tree, position) - const isInMiddleOfString = isCursorInEmptyString() + const isMultilineCompletion = getIsMultiLineCompletion() const isMultiLineCompletionNode = getIsMultiLineCompletionNode( this._currentNode ) this._isMultiLineCompletion = - isMultiLineCompletionNode && !isInMiddleOfString + isMultiLineCompletionNode && isMultilineCompletion } public async provideInlineCompletionItems( @@ -135,7 +135,7 @@ export class CompletionProvider implements InlineCompletionItemProvider { ) if ( - getIsMiddleOfWord() || + getIsMiddleWord() || isLastCompletionAccepted || this._lastCompletionMultiline ) { @@ -438,7 +438,9 @@ export class CompletionProvider implements InlineCompletionItemProvider { if (!editor || !this._position) return [] - const completionText = new CompletionFormatter(editor).format(this._completion) + const completionText = new CompletionFormatter(editor).format( + this._completion + ) if (this._cacheEnabled) cache.setCache(prefixSuffix, completionText) diff --git a/src/extension/utils.ts b/src/extension/utils.ts index e6c43390..b3cfb2ac 100644 --- a/src/extension/utils.ts +++ b/src/extension/utils.ts @@ -25,11 +25,9 @@ import { ALL_BRACKETS, API_PROVIDER, EXTENSION_NAME, - IMPORT_SEPARATOR, PROVIDER_NAMES, QUOTES, SKIP_DECLARATION_SYMBOLS, - SKIP_IMPORT_KEYWORDS_AFTER } from '../common/constants' import { Logger } from '../common/logger' @@ -85,9 +83,10 @@ export const getSkipVariableDeclataion = ( textAfter: string ) => { if ( + characterBefore && SKIP_DECLARATION_SYMBOLS.includes(characterBefore.trim()) && textAfter.length && - !textAfter.at(0) as unknown as string === '?' && + (!textAfter.at(0) as unknown as string) === '?' && !getIsOnlyBrackets(textAfter) ) { return true @@ -96,41 +95,6 @@ export const getSkipVariableDeclataion = ( return false } -export const getSkipImportDeclaration = ( - characterBefore: string, - textAfter: string -) => { - for (const skipWord of SKIP_IMPORT_KEYWORDS_AFTER) { - if ( - textAfter.includes(skipWord) && - !IMPORT_SEPARATOR.includes(characterBefore) && - characterBefore !== ' ' - ) { - return true - } - } - return false -} - -export const getCharacterBefore = (index = -1): string => { - const editor = window.activeTextEditor - if (!editor) return '' - const document = editor.document - const cursorPosition = editor.selection.active - const textBeforeRange = new Range(cursorPosition, new Position(0, 0)) - const textBefore = document.getText(textBeforeRange) - const characterBefore = textBefore.at(index) as string - - if (characterBefore === undefined) { - return SKIP_DECLARATION_SYMBOLS[0] - } - - if (!characterBefore.trim()) { - return getCharacterBefore(index - 1) - } - return characterBefore -} - export const getShouldSkipCompletion = ( context: InlineCompletionContext, disableAuto: boolean @@ -142,9 +106,11 @@ export const getShouldSkipCompletion = ( const lineEndPosition = document.lineAt(cursorPosition.line).range.end const textAfterRange = new Range(cursorPosition, lineEndPosition) const textAfter = document.getText(textAfterRange) - const characterBefore = getCharacterBefore() - if (getSkipVariableDeclataion(characterBefore, textAfter)) return true - if (getSkipImportDeclaration(characterBefore, textAfter)) return true + const { charBefore } = getBeforeAndAfter() + + if (getSkipVariableDeclataion(charBefore, textAfter)){ + return true + } return ( context.triggerKind === InlineCompletionTriggerKind.Automatic && disableAuto @@ -191,7 +157,7 @@ export const getPrefixSuffix = ( } } -export const getBeforeAndAfter = (matcher: (char: string) => boolean) => { +export const getBeforeAndAfter = () => { const editor = window.activeTextEditor if (!editor) return { @@ -204,14 +170,11 @@ export const getBeforeAndAfter = (matcher: (char: string) => boolean) => { const charBefore = lineText .substring(0, position.character) + .trim() .split('') - .reverse() - .find(matcher) + .reverse()[0] - const charAfter = lineText - .substring(position.character) - .split('') - .find(matcher) + const charAfter = lineText.substring(position.character).trim().split('')[0] return { charBefore, @@ -219,22 +182,30 @@ export const getBeforeAndAfter = (matcher: (char: string) => boolean) => { } } -export const isMiddleWord = () => { - const { charBefore, charAfter } = getBeforeAndAfter((char: string) => { - return /\w/.test(char) - }) +export const getIsMiddleWord = () => { + const { charBefore, charAfter } = getBeforeAndAfter() - return charBefore && charAfter && QUOTES?.includes(charAfter) + return ( + charBefore && charAfter && /\w/.test(charBefore) && /\w/.test(charAfter) + ) } -export const isCursorInEmptyString = () => { - const { charBefore, charAfter } = getBeforeAndAfter((char) => - QUOTES.includes(char) - ) +export const getHasLineTextBeforeAndAfter = () => { + const { charBefore, charAfter } = getBeforeAndAfter() return charBefore && charAfter } +export const isCursorInEmptyString = () => { + const { charBefore, charAfter } = getBeforeAndAfter() + + return QUOTES.includes(charBefore) && QUOTES.includes(charAfter) +} + +export const getIsMultiLineCompletion = () => { + return !getHasLineTextBeforeAndAfter() && !isCursorInEmptyString() +} + export const getTheme = () => { const currentTheme = window.activeColorTheme if (currentTheme.kind === ColorThemeKind.Light) { @@ -309,7 +280,10 @@ export const getNoTextBeforeOrAfter = () => { const editor = window.activeTextEditor const cursorPosition = editor?.selection.active if (!cursorPosition) return - const lastLinePosition = new Position(cursorPosition.line, editor.document.lineCount) + const lastLinePosition = new Position( + cursorPosition.line, + editor.document.lineCount + ) const textAfterRange = new Range(cursorPosition, lastLinePosition) const textAfter = editor?.document.getText(textAfterRange) const textBeforeRange = new Range(new Position(0, 0), cursorPosition) From 6345d8ac1cebd90a5c48cc64446e8620243716ce Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Mon, 25 Mar 2024 19:56:49 +0000 Subject: [PATCH 3/3] 3.8.19 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a27babfc..11f8fa4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "twinny", - "version": "3.8.18", + "version": "3.8.19", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twinny", - "version": "3.8.18", + "version": "3.8.19", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 07b42ba0..8dbc1e80 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "twinny", "displayName": "twinny - AI Code Completion and Chat", "description": "Locally hosted AI code completion plugin for vscode", - "version": "3.8.18", + "version": "3.8.19", "icon": "assets/icon.png", "keywords": [ "code-inference",