Skip to content

Commit

Permalink
Fix: Completion on Python
Browse files Browse the repository at this point in the history
  • Loading branch information
idillon-sfl authored and deribaucourt committed Nov 28, 2023
1 parent 77de4b1 commit e63ecea
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 23 deletions.
30 changes: 27 additions & 3 deletions client/src/language/middlewareCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,48 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */

import { type CompletionList, Uri, commands } from 'vscode'
import { type CompletionList, Uri, commands, Range } from 'vscode'
import { type CompletionMiddleware } from 'vscode-languageclient/node'

import { requestsManager } from './RequestManager'
import { getEmbeddedLanguageDocPosition } from './utils'
import { getEmbeddedLanguageDocPosition, getOriginalDocRange } from './utils'
import { getFileContent } from '../lib/src/utils/files'

export const middlewareProvideCompletion: CompletionMiddleware['provideCompletionItem'] = async (document, position, context, token, next) => {
const embeddedLanguageDocInfos = await requestsManager.getEmbeddedLanguageDocInfos(document.uri.toString(), position)
if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) {
return await next(document, position, context, token)
}
const adjustedPosition = await getEmbeddedLanguageDocPosition(document, embeddedLanguageDocInfos, position)
const embeddedLanguageDocContent = await getFileContent(Uri.parse(embeddedLanguageDocInfos.uri).fsPath)
if (embeddedLanguageDocContent === undefined) {
return
}
const adjustedPosition = getEmbeddedLanguageDocPosition(
document,
embeddedLanguageDocContent,
embeddedLanguageDocInfos.characterIndexes,
position
)
const vdocUri = Uri.parse(embeddedLanguageDocInfos.uri)
const result = await commands.executeCommand<CompletionList>(
'vscode.executeCompletionItemProvider',
vdocUri,
adjustedPosition,
context.triggerCharacter
)
result.items.forEach((item) => {
if (item.range === undefined) {
// pass
} else if (item.range instanceof Range) {
item.range = getOriginalDocRange(document, embeddedLanguageDocContent, embeddedLanguageDocInfos.characterIndexes, item.range)
} else {
const inserting = getOriginalDocRange(document, embeddedLanguageDocContent, embeddedLanguageDocInfos.characterIndexes, item.range.inserting)
const replacing = getOriginalDocRange(document, embeddedLanguageDocContent, embeddedLanguageDocInfos.characterIndexes, item.range.replacing)
if (inserting === undefined || replacing === undefined) {
return
}
item.range = { inserting, replacing }
}
})
return result
}
12 changes: 11 additions & 1 deletion client/src/language/middlewareHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ import { type Hover, Uri, commands } from 'vscode'

import { requestsManager } from './RequestManager'
import { getEmbeddedLanguageDocPosition } from './utils'
import { getFileContent } from '../lib/src/utils/files'

export const middlewareProvideHover: HoverMiddleware['provideHover'] = async (document, position, token, next) => {
const embeddedLanguageDocInfos = await requestsManager.getEmbeddedLanguageDocInfos(document.uri.toString(), position)
if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) {
return await next(document, position, token)
}
const adjustedPosition = await getEmbeddedLanguageDocPosition(document, embeddedLanguageDocInfos, position)
const embeddedLanguageDocContent = await getFileContent(Uri.parse(embeddedLanguageDocInfos.uri).fsPath)
if (embeddedLanguageDocContent === undefined) {
return
}
const adjustedPosition = getEmbeddedLanguageDocPosition(
document,
embeddedLanguageDocContent,
embeddedLanguageDocInfos.characterIndexes,
position
)
const vdocUri = Uri.parse(embeddedLanguageDocInfos.uri)
const result = await commands.executeCommand<Hover[]>(
'vscode.executeHoverProvider',
Expand Down
61 changes: 42 additions & 19 deletions client/src/language/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,45 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */

import fs from 'fs'
import { Position, Range, type TextDocument } from 'vscode'

import { type TextDocument, Position } from 'vscode'
export const getOriginalDocRange = (
originalTextDocument: TextDocument,
embeddedLanguageDocContent: string,
characterIndexes: number[],
embeddedRange: Range
): Range | undefined => {
const start = getOriginalDocPosition(originalTextDocument, embeddedLanguageDocContent, characterIndexes, embeddedRange.start)
const end = getOriginalDocPosition(originalTextDocument, embeddedLanguageDocContent, characterIndexes, embeddedRange.end)
if (start === undefined || end === undefined) {
return
}
return new Range(start, end)
}

import { type EmbeddedLanguageDocInfos } from '../lib/src/types/embedded-languages'
import { logger } from '../lib/src/utils/OutputLogger'
const getOriginalDocPosition = (
originalTextDocument: TextDocument,
embeddedLanguageDocContent: string,
characterIndexes: number[],
embeddedPosition: Position
): Position | undefined => {
const embeddedLanguageOffset = getOffset(embeddedLanguageDocContent, embeddedPosition)
const originalOffset = characterIndexes.findIndex(index => index === embeddedLanguageOffset)
if (originalOffset === -1) {
return
}
return originalTextDocument.positionAt(originalOffset)
}

export const getEmbeddedLanguageDocPosition = async (
export const getEmbeddedLanguageDocPosition = (
originalTextDocument: TextDocument,
embeddedLanguageDocInfos: EmbeddedLanguageDocInfos,
embeddedLanguageDocContent: string,
characterIndexes: number[],
originalPosition: Position
): Promise<Position | undefined> => {
): Position => {
const originalOffset = originalTextDocument.offsetAt(originalPosition)
const embeddedLanguageDocOffset = embeddedLanguageDocInfos.characterIndexes[originalOffset]
try {
const embeddedLanguageDocContent = await new Promise<string>((resolve, reject) => {
fs.readFile(embeddedLanguageDocInfos.uri.replace('file://', ''), { encoding: 'utf-8' },
(error, data) => { error !== null ? reject(error) : resolve(data) }
)
})
return getPosition(embeddedLanguageDocContent, embeddedLanguageDocOffset)
} catch (error) {
logger.error(`Failed to get embedded language document position: ${error as any}`)
return undefined
}
const embeddedLanguageDocOffset = characterIndexes[originalOffset]
return getPosition(embeddedLanguageDocContent, embeddedLanguageDocOffset)
}

const getPosition = (documentContent: string, offset: number): Position => {
Expand All @@ -43,3 +57,12 @@ const getPosition = (documentContent: string, offset: number): Position => {
}
return new Position(line, character)
}

const getOffset = (documentContent: string, position: Position): number => {
let offset = 0
for (let i = 0; i < position.line; i++) {
offset = documentContent.indexOf('\n', offset) + 1
}
offset += position.character
return offset
}
20 changes: 20 additions & 0 deletions client/src/lib/src/utils/files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2023 Savoir-faire Linux. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */

import fs from 'fs'

import { logger } from './OutputLogger'

export const getFileContent = async (path: string): Promise<string | undefined> => {
const fileContent = await new Promise<string>((resolve, reject) => {
fs.readFile(path, { encoding: 'utf-8' },
(error, data) => { error !== null ? reject(error) : resolve(data) }
)
}).catch(err => {
logger.error(`Could not open file: ${err}`)
return undefined
})
return fileContent
}

0 comments on commit e63ecea

Please sign in to comment.