Skip to content

Commit

Permalink
Adds support to manually refresh launcher (#1913)
Browse files Browse the repository at this point in the history
* Adds support to manually refresh launcher

* Minor UI tweaks

* Review feedback (#1914)

* Use rx observables throughout

Sort lexically on same dir level

* Better logging

---------

Co-authored-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
  • Loading branch information
pastuxso and sourishkrout authored Jan 17, 2025
1 parent 638424f commit b13d793
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 50 deletions.
24 changes: 20 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,13 @@
"category": "Runme",
"title": "Dispose terminal session to stop background task."
},
{
"command": "runme.refreshTasks",
"category": "Runme",
"title": "Refresh tasks",
"shortTitle": "Refresh",
"icon": "$(extensions-refresh)"
},
{
"command": "runme.collapseTreeView",
"category": "Runme",
Expand Down Expand Up @@ -496,6 +503,10 @@
"command": "runme.collapseTreeView",
"when": "false"
},
{
"command": "runme.refreshTasks",
"when": "false"
},
{
"command": "runme.expandTreeView",
"when": "false"
Expand Down Expand Up @@ -560,25 +571,30 @@
}
],
"view/title": [
{
"command": "runme.refreshTasks",
"when": "view == runme.launcher",
"group": "navigation@0"
},
{
"command": "runme.collapseTreeView",
"when": "view == runme.launcher && runme.launcher.isExpanded",
"group": "navigation"
"group": "navigation@1"
},
{
"command": "runme.expandTreeView",
"when": "view == runme.launcher && !runme.launcher.isExpanded",
"group": "navigation"
"group": "navigation@1"
},
{
"command": "runme.tasksIncludeUnnamed",
"when": "view == runme.launcher && !runme.launcher.includeUnnamed",
"group": "navigation"
"group": "navigation@1"
},
{
"command": "runme.tasksExcludeUnnamed",
"when": "view == runme.launcher && runme.launcher.includeUnnamed",
"group": "navigation"
"group": "navigation@1"
}
],
"explorer/context": [
Expand Down
6 changes: 6 additions & 0 deletions src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ export class RunmeExtension {
treeViewer.openCell.bind(treeViewer),
)
}
if (treeViewer.refreshTasks) {
RunmeExtension.registerCommand(
'runme.refreshTasks',
treeViewer.refreshTasks.bind(treeViewer),
)
}
} else {
treeViewer = new RunmeLauncherProvider(getDefaultWorkspace())
}
Expand Down
9 changes: 9 additions & 0 deletions src/extension/provider/launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ export interface RunmeTreeProvider extends TreeDataProvider<RunmeFile>, Disposab
openNotebook?(runmeFile: RunmeFile): Promise<void>
openCell?(runmeFile: RunmeFile): Promise<void>
runCell?(runmeFile: RunmeFile): Promise<void>
refreshTasks?(): Promise<void>
onDidRefresh(callback: VoidFunction): Promise<void>
}

export class RunmeLauncherProvider implements RunmeTreeProvider {
Expand All @@ -97,6 +99,7 @@ export class RunmeLauncherProvider implements RunmeTreeProvider {

private filesTree: Map<string, TreeFile> = new Map()
private defaultItemState: TreeItemCollapsibleState = TreeItemCollapsibleState.Collapsed
private _onDidRefresh: EventEmitter<void> = new EventEmitter<void>()

constructor(private workspaceRoot?: string | undefined) {
const watcher = workspace.createFileSystemWatcher(GLOB_PATTERN, false, true, false)
Expand All @@ -106,6 +109,12 @@ export class RunmeLauncherProvider implements RunmeTreeProvider {
)
}

onDidRefresh(_callback: VoidFunction): Promise<void> {
return new Promise<void>((resolve) => {
resolve()
})
}

public get includeAllTasks(): boolean {
return this._includeAllTasks
}
Expand Down
17 changes: 16 additions & 1 deletion src/extension/provider/launcherBeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class RunmeLauncherProvider implements RunmeTreeProvider {
private defaultItemState = TreeItemCollapsibleState.Collapsed
private _onDidChangeTreeData = new EventEmitter<RunmeFile | undefined>()
private notebooks: RunmeFile[] = []
private _onDidRefresh: EventEmitter<void> = new EventEmitter<void>()

constructor(
private kernel: Kernel,
Expand All @@ -56,6 +57,21 @@ export class RunmeLauncherProvider implements RunmeTreeProvider {
this._onDidChangeTreeData.fire(undefined)
}

onDidRefresh(callback: VoidFunction): Promise<void> {
return new Promise<void>((resolve) => {
this._onDidRefresh.event(() => {
callback()
this._onDidChangeTreeData.fire(undefined)
resolve()
})
})
}

async refreshTasks() {
this.notebooks = []
this._onDidRefresh.fire(undefined)
}

async excludeUnnamed() {
this.allowUnnamed = false
this.notebooks = []
Expand All @@ -80,7 +96,6 @@ export class RunmeLauncherProvider implements RunmeTreeProvider {
}

getTreeItem(element: RunmeFile): TreeItem {
console.log(`Node contextValue: ${element.contextValue}`)
return element
}

Expand Down
129 changes: 84 additions & 45 deletions src/extension/provider/runmeTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import {
from,
map,
firstValueFrom,
lastValueFrom,
isObservable,
toArray,
mergeMap,
delayWhen,
finalize,
} from 'rxjs'

import getLogger from '../logger'
Expand Down Expand Up @@ -103,70 +105,107 @@ export class RunmeTaskProvider implements TaskProvider {
})
})

this.tasks = lastValueFrom(this.loadProjectTasks())
// returns this.tasks to conform to non-null
this.tasks = this.refreshTasks()

treeView.onDidRefresh(() => {
this.refreshTasks()
})
}

private async initProjectClient(transport?: GrpcTransport) {
this.client = initProjectClient(transport ?? (await this.server.transport()))
}

protected loadProjectTasks(): Observable<ProjectTask[]> {
public refreshTasks(): Promise<ProjectTask[]> {
if (!workspace.workspaceFolders?.length) {
return Promise.resolve([])
}

this.tasks = firstValueFrom(this.loadProjectTasks())

return this.tasks
}

private loadProjectTasks(): Observable<ProjectTask[]> {
if (!workspace.workspaceFolders?.length) {
return of([])
}

const separator = workspace.workspaceFolders[0].uri.fsPath.indexOf('/') > -1 ? '/' : '\\'

const requests = (workspace.workspaceFolders ?? []).map((folder) => {
return <LoadRequest>{
kind: {
oneofKind: 'directory',
directory: {
path: workspace.asRelativePath(folder.uri),
skipGitignore: false,
ignoreFilePatterns: [],
skipRepoLookupUpward: false,
},
},
identity: RunmeIdentity.ALL,
}
})
const folders$ = of(workspace.workspaceFolders).pipe(
mergeMap((folders) => {
log.info(`Walking ${folders.length} directories/repos...`)
return from(folders).pipe(
map((folder) => {
return <LoadRequest>{
kind: {
oneofKind: 'directory',
directory: {
path: workspace.asRelativePath(folder.uri),
skipGitignore: false,
ignoreFilePatterns: [],
skipRepoLookupUpward: false,
},
},
identity: RunmeIdentity.ALL,
}
}),
)
}),
)

log.info(`Walking ${requests.length} directories/repos...`)

const task$ = new Observable<ProjectTask>((observer) => {
this.ready.then(() =>
Promise.all(
requests.map((request) => {
const session: LoadStream = this.client!.load(request)
session.responses.onMessage((msg) => {
if (msg.data.oneofKind !== 'foundTask') {
return
}
observer.next(msg.data.foundTask)
})
return session
const task$ = folders$.pipe(
delayWhen(() => from(this.ready)),
mergeMap((folder) => {
return new Observable<ProjectTask>((observer) => {
const session: LoadStream = this.client!.load(folder)
session.responses.onMessage((msg) => {
if (msg.data.oneofKind !== 'foundTask') {
return
}
observer.next(msg.data.foundTask)
})
session.responses.onError((err) => observer.error(err))
session.responses.onComplete(() => observer.complete())
}).pipe(
finalize(() => {
if (folder.kind.oneofKind !== 'directory') {
return
}
log.info(`Finished walk ${folder.kind.directory.path}.`)
}),
).then(() => {
log.info('Finished walk.')
observer.complete()
)
}),
)

const dirProx = RunmeTaskProvider.directoryPromximityComp()
return task$.pipe(
toArray(),
map((tasks) =>
tasks.sort((a, b) => {
const delta = dirProx(a.documentPath) - dirProx(b.documentPath)
if (delta === 0) {
return a.documentPath.localeCompare(b.documentPath)
}
return delta
}),
)
})
),
)
}

const dirProx = (pt: ProjectTask) => {
const { relativePath, outside } = asWorkspaceRelativePath(pt.documentPath)
public static directoryPromximityComp = () => {
let separator = '/'
if (!!workspace.workspaceFolders?.length) {
separator = workspace.workspaceFolders[0].uri.fsPath.indexOf('/') > -1 ? '/' : '\\'
}
return function (path: string) {
const { relativePath, outside } = asWorkspaceRelativePath(path)
const len = relativePath.split(separator).length
if (outside) {
return 100 * len
}
return len
}

return task$.pipe(
toArray(),
map((tasks) => tasks.sort((a, b) => dirProx(a) - dirProx(b))),
)
}

public async provideTasks(token: CancellationToken): Promise<Task[]> {
Expand Down

0 comments on commit b13d793

Please sign in to comment.