Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
feat: add configuration to enable/disable RCC live execution
Browse files Browse the repository at this point in the history
  • Loading branch information
seanwu1105 committed Feb 12, 2023
1 parent 003e28d commit 99f3f79
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 7 deletions.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@
"markdownDescription": "The options passed to Qt `qmlls` executable. See [here](https://github.com/seanwu1105/vscode-qt-for-python#predefined-variables) for a detailed list of predefined variables.",
"scope": "window"
},
"qtForPython.rcc.liveExecution": {
"type": "boolean",
"default": true,
"markdownDescription": "Enable live execution of Qt `rcc` executable. This will automatically compile the resource file when it is saved.",
"scope": "resource"
},
"qtForPython.rcc.path": {
"type": "string",
"default": "",
Expand Down
38 changes: 33 additions & 5 deletions src/rcc/rcc-live-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ import type { X2jOptionsOptional } from 'fast-xml-parser'
import { XMLParser } from 'fast-xml-parser'
import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { concatMap, defer, from, merge, mergeMap, of, startWith } from 'rxjs'
import {
concatMap,
defer,
firstValueFrom,
from,
merge,
mergeMap,
of,
startWith,
} from 'rxjs'
import { RelativePattern, workspace } from 'vscode'
import { URI } from 'vscode-uri'
import { z } from 'zod'
import { getConfiguration$ } from '../configurations'
import { EXTENSION_NAMESPACE } from '../constants'
import type { ErrorResult, SuccessResult } from '../types'
import { getWatcher$ } from '../watcher'
import { compileResource } from './compile-resource'

export function registerRccLiveExecution$({
extensionUri,
}: RegisterRccLiveExecutionArgs) {
const qrcFiles$ = defer(async () => workspace.findFiles('**/*.qrc')).pipe(
concatMap(uris => from(uris)),
)
const qrcFiles$ = defer(async () =>
workspace.findFiles('**/*.qrc', '**/site-packages/**'),
).pipe(concatMap(uris => from(uris)))

return merge(qrcFiles$, getWatcher$('**/*.qrc')).pipe(
mergeMap(qrcUri =>
Expand All @@ -40,7 +51,24 @@ function registerResourcesLiveExecution$({
...result.value.map(uri => getWatcher$(new RelativePattern(uri, '*'))),
).pipe(
startWith(undefined), // Trigger compilation on resource file changes
concatMap(async () => compileResource({ extensionUri }, qrcUri)),
concatMap(() =>
firstValueFrom(
getConfiguration$({
section: `${EXTENSION_NAMESPACE}.rcc`,
key: 'liveExecution',
defaultValue: true,
resource: qrcUri,
}),
),
),
concatMap(async enabled => {
if (!enabled)
return {
kind: 'Success',
value: 'Live execution disabled',
} as const
return compileResource({ extensionUri }, qrcUri)
}),
)
}),
)
Expand Down
11 changes: 10 additions & 1 deletion src/test/suite/qss/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@ import * as path from 'node:path'
import type { ColorInformation, TextDocument } from 'vscode'
import { commands, window, workspace } from 'vscode'
import { URI } from 'vscode-uri'
import { E2E_TIMEOUT, TEST_ASSETS_PATH } from '../test-utils'
import {
E2E_TIMEOUT,
setupE2EEnvironment,
TEST_ASSETS_PATH,
} from '../test-utils'

suite('qss/e2e', () => {
suiteSetup(async function () {
this.timeout(E2E_TIMEOUT)
await setupE2EEnvironment()
})

suite('color picker', () => {
suite('when open QLabel.qss', () => {
let document: TextDocument
Expand Down
126 changes: 126 additions & 0 deletions src/test/suite/rcc/rcc-live-execution.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import * as assert from 'node:assert'
import * as fs from 'node:fs'
import * as path from 'node:path'
import {
E2E_TIMEOUT,
setupE2EEnvironment,
sleep,
TEST_ASSETS_PATH,
waitFor,
} from '../test-utils'

suite('rcc-live-execution/e2e', () => {
const sampleQrcFilenameNoExt = 'sample'

let originalFullText: string

suiteSetup(async function () {
this.timeout(E2E_TIMEOUT)
await setupE2EEnvironment()
})

setup(async function () {
this.timeout(E2E_TIMEOUT)
await removeGeneratedFile(sampleQrcFilenameNoExt)
})

teardown(async function () {
this.timeout(E2E_TIMEOUT)
await removeGeneratedFile(sampleQrcFilenameNoExt)
})

suite('when qrc file changed', () => {
const qrcFilePath = path.resolve(
TEST_ASSETS_PATH,
'qrc',
`${sampleQrcFilenameNoExt}.qrc`,
)

setup(async function () {
this.timeout(E2E_TIMEOUT)
originalFullText = fs.readFileSync(qrcFilePath, { encoding: 'utf-8' })
})

teardown(function () {
this.timeout(E2E_TIMEOUT)
fs.writeFileSync(qrcFilePath, originalFullText, { encoding: 'utf-8' })
})

test('should recompile', async () => {
fs.writeFileSync(
qrcFilePath,
originalFullText.replace(/<file>rc0.txt<\/file>/gi, ''),
)

await waitFor(() =>
assert.ok(
fs.existsSync(
path.resolve(
TEST_ASSETS_PATH,
'qrc',
`rc_${sampleQrcFilenameNoExt}.py`,
),
),
),
)
}).timeout(E2E_TIMEOUT)
})

suite('when a resource file changed', () => {
const sampleResourceFilename = 'rc1.txt'

const resourceFilePath = path.resolve(
TEST_ASSETS_PATH,
'qrc',
sampleResourceFilename,
)

setup(async function () {
this.timeout(E2E_TIMEOUT)
originalFullText = fs.readFileSync(resourceFilePath, {
encoding: 'utf-8',
})
})

teardown(function () {
this.timeout(E2E_TIMEOUT)
fs.writeFileSync(resourceFilePath, originalFullText, {
encoding: 'utf-8',
})
})

test('should recompile', async () => {
fs.writeFileSync(
resourceFilePath,
originalFullText.replace(/hello/gi, 'world'),
)

await waitFor(() =>
assert.ok(
fs.existsSync(
path.resolve(
TEST_ASSETS_PATH,
'qrc',
`rc_${sampleQrcFilenameNoExt}.py`,
),
),
),
)
})
})
}).timeout(E2E_TIMEOUT)

async function removeGeneratedFile(sampleFilenameNoExt: string) {
return waitFor(async () => {
await sleep() // Wait for the file to be created asynchronously by the extension
fs.rmSync(
path.resolve(TEST_ASSETS_PATH, 'qrc', `rc_${sampleFilenameNoExt}.py`),
{ force: true, recursive: true },
)
assert.ok(
!fs.existsSync(
path.resolve(TEST_ASSETS_PATH, 'qrc', `rc_${sampleFilenameNoExt}.py`),
),
)
})
}
1 change: 1 addition & 0 deletions src/test/suite/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export async function sleep(ms = DEFAULT_TIMEOUT) {
return new Promise(resolve => setTimeout(resolve, ms))
}

// TODO: This might not be necessary
export async function setupE2EEnvironment() {
await sleep() // wait for extension to load Extension Gallery

Expand Down
2 changes: 1 addition & 1 deletion src/test/suite/uic/uic-live-execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ suite('uic-live-execution/e2e', () => {
removeGeneratedFile(sampleFilenameNoExt)
})

test('should recompile UI file changed', async () => {
test('should recompile when UI file changed', async () => {
fs.writeFileSync(
uiFilePath,
originalFullText.replace(/My Window Title/gi, 'My New Window Title'),
Expand Down

0 comments on commit 99f3f79

Please sign in to comment.