Skip to content

Commit

Permalink
Merge pull request #170 from rjmacarthy/development
Browse files Browse the repository at this point in the history
development > main
  • Loading branch information
rjmacarthy committed Mar 5, 2024
2 parents 4b350e3 + 15e5512 commit 2b2701e
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 46 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "twinny",
"displayName": "twinny - AI Code Completion and Chat",
"description": "Locally hosted AI code completion plugin for vscode",
"version": "3.7.11",
"version": "3.7.12",
"icon": "assets/icon.png",
"keywords": [
"code-inference",
Expand Down Expand Up @@ -306,7 +306,7 @@
"twinny.contextLength": {
"order": 11,
"type": "number",
"default": 30,
"default": 100,
"description": "Defines the number of lines before and after the current line to include in FIM prompts.",
"required": true
},
Expand Down
5 changes: 4 additions & 1 deletion src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export const NORMALIZE_REGEX = /\s*\r?\n|\r/g;
export const LINE_BREAK_REGEX = /\r?\n|\r|\n/g
export const COMPLETION_TIMEOUT = 20000 // 20 seconds
export const MAX_CONTEXT_LINE_COUNT = 200
export const SKIP_DECLARATION_SYMBOLS = ['=', ':']
export const IMPORT_SEPARATOR = [',', '{']
export const SKIP_IMPORT_KEYWORDS_AFTER = ['from', 'as', 'import']

export const MESSAGE_NAME = {
twinnyAcceptSolution: 'twinny-accept-solution',
Expand Down Expand Up @@ -49,7 +52,7 @@ export const MESSAGE_NAME = {
twinnyFetchOllamaModels: 'twinny-fetch-ollama-models',
twinnySetOllamaModel: 'twinny-set-ollama-model',
twinnySetConfigValue: 'twinny-set-config-value',
twinnyGetConfigValue: 'twinnyGetConfigValue',
twinnyGetConfigValue: 'twinny-get-config-value',
}

export const MESSAGE_KEY = {
Expand Down
41 changes: 17 additions & 24 deletions src/extension/completion-formatter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { Position, Range, TextEditor } from 'vscode'

import {
ALL_BRACKETS,
CLOSING_BRACKETS,
OPENING_BRACKETS,
QUOTES
} from '../common/constants'
import { CLOSING_BRACKETS, OPENING_BRACKETS, QUOTES } from '../common/constants'
import { Bracket } from '../common/types'

export class CompletionFormatter {
Expand Down Expand Up @@ -86,20 +81,6 @@ export class CompletionFormatter {
return this
}

private isSingleBracket = (completion: string) =>
completion.length === 1 && this.isBracket(completion)

private isOnlyBrackets(completion: string): boolean {
if (completion.length === 0) return false

for (const char of completion) {
if (!this.isBracket(char)) {
return false
}
}
return true
}

private normalise = (text: string) => text?.trim()

private removeDuplicateText() {
Expand Down Expand Up @@ -185,10 +166,6 @@ export class CompletionFormatter {
return this
}

private isBracket = (char: string): char is Bracket => {
return ALL_BRACKETS.includes(char as Bracket)
}

private preventDuplicateLines = (): CompletionFormatter => {
const lineCount = this._editor.document.lineCount
let nextLineIndex = this._cursorPosition.line + 1
Expand Down Expand Up @@ -223,6 +200,21 @@ export class CompletionFormatter {
return this
}

private skipSimilarCompletions = () => {
const textAfter = this._editor.document.getText(
new Range(
this._cursorPosition,
this._editor.document.lineAt(this._cursorPosition.line).range.end
)
)

const score = this._completion.score(textAfter)

if (score > 0.5) this._completion = ''

return this
}

private getCompletion = () => {
if (this._completion.trim().length === 0) {
this._completion = ''
Expand All @@ -249,6 +241,7 @@ export class CompletionFormatter {
.removeInvalidLineBreaks()
.removeDuplicateText()
.skipMiddleOfWord()
.skipSimilarCompletions()
.getCompletion()
return infillText
}
Expand Down
33 changes: 18 additions & 15 deletions src/extension/providers/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import {
window,
Uri,
InlineCompletionContext,
InlineCompletionTriggerKind
} from 'vscode'
import AsyncLock from 'async-lock'
import 'string_score'
import { getFimDataFromProvider, getPrefixSuffix } from '../utils'
import { getFimDataFromProvider, getPrefixSuffix, getShouldSkipCompletion } from '../utils'
import { cache } from '../cache'
import { supportedLanguages } from '../../common/languages'
import {
Expand All @@ -24,7 +23,10 @@ import {
StreamResponse
} from '../../common/types'
import { getFimPrompt, getStopWords } from '../fim-templates'
import { LINE_BREAK_REGEX, MAX_CONTEXT_LINE_COUNT } from '../../common/constants'
import {
LINE_BREAK_REGEX,
MAX_CONTEXT_LINE_COUNT,
} from '../../common/constants'
import { streamResponse } from '../stream'
import { createStreamRequestBody } from '../model-options'
import { Logger } from '../../common/logger'
Expand Down Expand Up @@ -85,7 +87,7 @@ export class CompletionProvider implements InlineCompletionItemProvider {
context: InlineCompletionContext
): Promise<InlineCompletionItem[] | InlineCompletionList | null | undefined> {
const editor = window.activeTextEditor
if (this.shouldSkipCompletion(context) || !editor || !this._enabled) return
if (getShouldSkipCompletion(context, this._disableAuto) || !editor || !this._enabled) return
this._document = document
this._position = position
this._chunkCount = 0
Expand Down Expand Up @@ -144,7 +146,9 @@ export class CompletionProvider implements InlineCompletionItemProvider {

private isMiddleWord(prefixSuffix: PrefixSuffix) {
const { prefix, suffix } = prefixSuffix
return /\w/.test(prefix.at(-1) as string) && /\w/.test(suffix.at(0) as string)
return (
/\w/.test(prefix.at(-1) as string) && /\w/.test(suffix.at(0) as string)
)
}

private buildStreamRequest(prompt: string) {
Expand Down Expand Up @@ -272,8 +276,14 @@ export class CompletionProvider implements InlineCompletionItemProvider {
const averageLine =
activeLines.reduce((acc, curr) => acc + curr.line, 0) /
activeLines.length
const start = new Position(Math.max(0, Math.ceil(averageLine || 0) - 100), 0)
const end = new Position(Math.min(lineCount, Math.ceil(averageLine || 0) + 100), 0)
const start = new Position(
Math.max(0, Math.ceil(averageLine || 0) - 100),
0
)
const end = new Position(
Math.min(lineCount, Math.ceil(averageLine || 0) + 100),
0
)
fileChunks.push(`
// File: ${filePath}
// Content: \n ${document.getText(new Range(start, end))}
Expand All @@ -295,16 +305,9 @@ export class CompletionProvider implements InlineCompletionItemProvider {
})
}

private shouldSkipCompletion(context: InlineCompletionContext) {
return (
context.triggerKind === InlineCompletionTriggerKind.Automatic &&
this._disableAuto
)
}

private getContainsStopWord() {
return this._stopWords.some((stopSequence) =>
this._completion?.includes(stopSequence)
this._completion.includes(stopSequence)
)
}

Expand Down
81 changes: 79 additions & 2 deletions src/extension/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
ColorThemeKind,
ConfigurationTarget,
InlineCompletionContext,
InlineCompletionTriggerKind,
Position,
Range,
TextDocument,
Expand All @@ -15,13 +17,18 @@ import {
ApiProviders,
StreamResponse,
StreamRequest,
PrefixSuffix
PrefixSuffix,
Bracket
} from '../common/types'
import { supportedLanguages } from '../common/languages'
import {
ALL_BRACKETS,
API_PROVIDER,
EXTENSION_NAME,
PROVIDER_NAMES
IMPORT_SEPARATOR,
PROVIDER_NAMES,
SKIP_DECLARATION_SYMBOLS,
SKIP_IMPORT_KEYWORDS_AFTER
} from '../common/constants'
import { Logger } from '../common/logger'

Expand Down Expand Up @@ -54,6 +61,76 @@ export const getLanguage = (): LanguageType => {
}
}

export const getIsBracket = (char: string): char is Bracket => {
return ALL_BRACKETS.includes(char as Bracket)
}

export const getIsSingleBracket = (completion: string) =>
completion.length === 1 && getIsBracket(completion)

export const getIsOnlyBrackets = (completion: string) => {
if (completion.length === 0) return false

for (const char of completion) {
if (!getIsBracket(char)) {
return false
}
}
return true
}

export const getSkipVariableDeclataion = (
characterBefore: string,
textAfter: string
) => {
if (
SKIP_DECLARATION_SYMBOLS.includes(characterBefore.trim()) &&
textAfter.length &&
!getIsOnlyBrackets(textAfter)
) {
return true
}
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 getShouldSkipCompletion = (
context: InlineCompletionContext,
disableAuto: boolean
) => {
const editor = window.activeTextEditor
if (!editor) return true
const document = editor.document
const cursorPosition = editor.selection.active
const lineEndPosition = document.lineAt(cursorPosition.line).range.end
const textAfterRange = new Range(cursorPosition, lineEndPosition)
const textBeforeRange = new Range(cursorPosition, new Position(0, 0))
const textAfter = document.getText(textAfterRange)
const textBefore = document.getText(textBeforeRange)
const characterBefore = textBefore.at(-1) as string
if (getSkipVariableDeclataion(characterBefore, textAfter)) return true
if (getSkipImportDeclaration(characterBefore, textAfter)) return true

return (
context.triggerKind === InlineCompletionTriggerKind.Automatic && disableAuto
)
}

export const getPrefixSuffix = (
numLines: number,
document: TextDocument,
Expand Down

0 comments on commit 2b2701e

Please sign in to comment.