Skip to content

Commit

Permalink
Merge branch 'savoirfairelinux:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
deribaucourt authored Nov 28, 2023
2 parents 741adcf + 4a4dc7b commit 9264a6a
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 161 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: vscode-bitbake
path: client/bitbake*.vsix
path: client/yocto-bitbake*.vsix
1 change: 0 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"args": [
"--extensionDevelopmentPath=${workspaceRoot}/client",
"--extensionTestsPath=${workspaceRoot}/integration-tests/out/index",
"--disable-extensions",
"--disable-workspace-trust",
"${workspaceRoot}/integration-tests/project-folder"
],
Expand Down
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ Manual installation takes place in two steps. The code must be installed via `np
### Commands

To install the dependencies:
```
``` sh
npm install
```
To compile the typescript files:
```
``` sh
npm run compile
```
To clean up the project (This deletes node_modules):
```
``` sh
npm run clean
```
For more commands, refer to the `script` section in the root `package.json`.
Expand All @@ -37,32 +37,35 @@ Press `F5` or navigate to the debug section on the left of the VS Code and selec

## Testing

Bitbake and Yocto docs are required for some features to work, They need to be fetched before testing and development:

$ npm run fetch:docs

BitBake and Yocto docs are required for some features to work. They need to be fetched before testing and development:
``` sh
npm run fetch:docs
```
Similar for the command that fetches poky, it needs to be run before running the integration tests:

$ npm run fetch:poky

``` sh
npm run fetch:poky
```
A wrapper npm script allows running several kinds of tests. To run all tests, use:

$ npm test

``` sh
npm test
```
All the tests mentionned are run in our GitHub CI.

### Linter tests

One can check coding style using `npm run lint`.
One can check coding style using
``` sh
npm run lint
```
Install the recommended extensions to automatically fix linting errors when possible.

### Unit tests

Unit tests are powered by Jest. They allow mocking the behavior of VSCode
and other external libraries. They can individually be run with:

$ npm run jest

```sh
npm run jest
```
Unit tests are defined in the `__tests__` folders.

If you have installed the recommended extensions, you'll find launch and debug
Expand All @@ -74,7 +77,7 @@ See [the individual grammar tests README](client/test/grammars/README.md).

### Integration tests

These tests allow running the bitbake extension in a live VSCode environment.
These tests allow running the BitBake extension in a live VSCode environment.
See [the individual integration tests README](integration-tests/README.md).

## Tree-sitter
Expand Down
4 changes: 2 additions & 2 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Here's an example `settings.json` reflecting the default values:

### Syntax highlighting

The extension provides syntax highlighting for BitBake recipes, classes, configuration and inc-files. Syntax highlighting also supports embedded languages inside bitbake recipes including inline Python variable expansion, shell code and Python code.
The extension provides syntax highlighting for BitBake recipes, classes, configuration and inc-files. Syntax highlighting also supports embedded languages inside BitBake recipes including inline Python variable expansion, shell code and Python code.

The BitBake language is automatically detected based on the file extension:
[`.bb`, `.bbappend`, `.bbclass`]. [`.conf`, `.inc`] are also supported but may be used by other tools.
Expand Down Expand Up @@ -105,7 +105,7 @@ By default, this extension will run BitBake in parse only mode in the background

### BitBake status bar

Bitbake parsing status is displayed in the status bar at the bottom of the screen. It will show wether the last BitBake run was successful or not. The bitbake server queues all BitBake commands and runs them sequentially. The status bar will show you if the extension is currently trying to access the bitbake server.
Bitbake parsing status is displayed in the status bar at the bottom of the screen. It will show wether the last BitBake run was successful or not. The BitBake server queues all BitBake commands and runs them sequentially. The status bar will show you if the extension is currently trying to access the bitbake server.

![Status bar](doc/status-bar.gif)

Expand Down
4 changes: 4 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"engines": {
"vscode": "^1.75.0"
},
"extensionDependencies": [
"mads-hartmann.bash-ide-vscode",
"ms-python.python"
],
"categories": [
"Programming Languages"
],
Expand Down
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
}
19 changes: 19 additions & 0 deletions client/syntaxes/bitbake.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@
},
"string": {
"patterns": [
{
"name": "string.quoted.triple.bb",
"begin": "(\"\"\")",
"end": "(\"\"\")",
"patterns": [
{
"include": "#escaped-single-quote"
},
{
"include": "#escaped-double-quote"
},
{
"include": "#inline-python"
},
{
"include": "#variable-expansion"
}
]
},
{
"name": "string.quoted.double.bb",
"begin": "(\")",
Expand Down
6 changes: 6 additions & 0 deletions client/test/grammars/snaps/strings.bb
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,9 @@ INHERIT += "autotools pkgconfig"
MYVAR = "This string contains escaped double quote \" and it should not break the highlight"

MYVAR = 'This string contains escaped single quote \' and it should not break the highlight'

MYVAR = """
nested " quotes shoudn't change the highlighting
"""

TEST_TRIPLE_QUOTES = 'the highlighting for this line which follows the triple quotes should still work correctly'
15 changes: 15 additions & 0 deletions client/test/grammars/test-cases/strings.bb
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,18 @@
# ^^ source.bb string.quoted.single.bb constant.character.escape.bb
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.bb string.quoted.single.bb
# ^ source.bb string.quoted.single.bb

>MYVAR = """
# ^^^ source.bb string.quoted.triple.bb
>nested " quotes shoudn't change the highlighting
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.bb string.quoted.triple.bb
>"""
#^^^ source.bb string.quoted.triple.bb
>
>TEST_TRIPLE_QUOTES = 'the highlighting for this line which follows the triple quotes should still work correctly'
#^^^^^^^^^^^^^^^^^^ source.bb variable.other.names.bb
# ^ source.bb keyword.operator.bb
# ^ source.bb string.quoted.single.bb
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.bb string.quoted.single.bb
# ^ source.bb string.quoted.single.bb
>
6 changes: 4 additions & 2 deletions integration-tests/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Integration tests

The integration tests allow running the bitbake extension in a live VSCode
The integration tests allow running the extension in a live VSCode
environment.

## Running the integration tests
Expand All @@ -13,7 +13,9 @@ This can be done by running our `npm fetch:poky` script. It requires `curl` and
The npm script `test:integration` will run the integration tests.

It will run VSCode in headless mode. Make sure to have installed the dependency:
$ apt install xvfb
``` sh
apt install xvfb
```

## Debugging the integration tests

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/remote-session/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ This test is unfortunately not automated yet.
4. Connect to the container using the Remote SSH extension. An example ssh.config file is provided.
5. Install the extension on the remote container: Extensions->Local->Bitbake->Install in SSH
6. Within the remote session, open the workspace in `/home/yoctouser/vscode-bitbake/integration-tests/project-folder`
7. Open recipes, run bitbake commands...
7. Open recipes, run BitBake commands...
Loading

0 comments on commit 9264a6a

Please sign in to comment.