Skip to content

Commit bb5f7ec

Browse files
committed
Add check definition and references commands to improve code navigation and context management
1 parent c01a3b2 commit bb5f7ec

11 files changed

Lines changed: 344 additions & 27 deletions

File tree

‎PRIVACY.md‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
# Privacy Policy
22

3-
Code Web Chat is **privacy-first**. We adhere to a **strict zero telemetry policy**.
3+
Code Web Chat is **privacy-first**.
44

55
**No Data Collection** \
66
The extension does not collect, store, or transmit any telemetry data.
77

88
**Local Operation** \
9-
All operations are performed locally on your machine.
10-
11-
**Direct Communication** \
12-
Prompts are sent directly from your browser to the chatbots or from your editor to the model providers you configure.
9+
Chatbot/API responses are processed on your machine.

‎apps/editor/package.json‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@
324324
"title": "Check All with Keywords...",
325325
"category": "Code Web Chat"
326326
},
327+
{
328+
"command": "codeWebChat.checkReferences",
329+
"title": "Check References",
330+
"category": "Code Web Chat"
331+
},
332+
{
333+
"command": "codeWebChat.checkDefinition",
334+
"title": "Check Definition",
335+
"category": "Code Web Chat"
336+
},
327337
{
328338
"command": "codeWebChat.openInIntegratedTerminal",
329339
"title": "Open in Integrated Terminal",
@@ -340,7 +350,8 @@
340350
"menus": {
341351
"editor/context": [
342352
{
343-
"submenu": "codeWebChat.editorSubmenu"
353+
"submenu": "codeWebChat.editorSubmenu",
354+
"group": "navigation@1000"
344355
}
345356
],
346357
"codeWebChat.editorSubmenu": [
@@ -359,6 +370,14 @@
359370
{
360371
"command": "codeWebChat.codeAtCursorWithInstructionsUsing",
361372
"group": "1_action@4"
373+
},
374+
{
375+
"command": "codeWebChat.checkDefinition",
376+
"group": "1_action@6"
377+
},
378+
{
379+
"command": "codeWebChat.checkReferences",
380+
"group": "1_action@5"
362381
}
363382
],
364383
"commandPalette": [
@@ -477,6 +496,14 @@
477496
{
478497
"command": "codeWebChat.copyCommitMessagePrompt",
479498
"when": "false"
499+
},
500+
{
501+
"command": "codeWebChat.checkDefinition",
502+
"when": "false"
503+
},
504+
{
505+
"command": "codeWebChat.checkReferences",
506+
"when": "false"
480507
}
481508
],
482509
"view/title": [

‎apps/editor/src/commands/check-all-with-keywords.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,20 @@ export const check_all_with_keywords_command = (
138138
matched_files.length == 1 ? '' : 's'
139139
}`
140140
quick_pick.ignoreFocusOut = true
141+
quick_pick.buttons = [close_button]
141142

142143
const selected_items = await new Promise<
143144
readonly (vscode.QuickPickItem & { file_path: string })[] | undefined
144145
>((resolve) => {
145146
let is_accepted = false
146147

148+
quick_pick.onDidTriggerButton((button) => {
149+
if (button === close_button) {
150+
resolve(undefined)
151+
quick_pick.hide()
152+
}
153+
})
154+
147155
quick_pick.onDidAccept(() => {
148156
is_accepted = true
149157
resolve(quick_pick.selectedItems)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import * as vscode from 'vscode'
2+
import { WorkspaceProvider } from '../context/providers/workspace/workspace-provider'
3+
import { Logger } from '@shared/utils/logger'
4+
5+
export const check_definition_command = (
6+
workspace_provider: WorkspaceProvider
7+
) => {
8+
return vscode.commands.registerCommand(
9+
'codeWebChat.checkDefinition',
10+
async () => {
11+
const editor = vscode.window.activeTextEditor
12+
if (!editor) {
13+
return
14+
}
15+
16+
try {
17+
const document = editor.document
18+
const position = editor.selection.active
19+
20+
const definition_uri = await vscode.window.withProgress(
21+
{
22+
location: vscode.ProgressLocation.Window,
23+
title: 'Resolving definition...'
24+
},
25+
async () => {
26+
const result = await vscode.commands.executeCommand<
27+
vscode.Location | vscode.Location[] | vscode.LocationLink[]
28+
>('vscode.executeDefinitionProvider', document.uri, position)
29+
30+
if (!result) return null
31+
32+
if (Array.isArray(result)) {
33+
if (result.length === 0) return null
34+
const first = result[0]
35+
return 'targetUri' in first ? first.targetUri : first.uri
36+
} else {
37+
return (result as vscode.Location).uri
38+
}
39+
}
40+
)
41+
42+
if (!definition_uri) {
43+
vscode.window.showInformationMessage('No definition found.')
44+
return
45+
}
46+
47+
const file_path = definition_uri.fsPath
48+
49+
if (!workspace_provider.get_workspace_root_for_file(file_path)) {
50+
vscode.window.showWarningMessage(
51+
'Definition found is outside the workspace.'
52+
)
53+
return
54+
}
55+
56+
if (workspace_provider.is_ignored_by_patterns(file_path)) {
57+
vscode.window.showWarningMessage(
58+
'Definition found is in an ignored file.'
59+
)
60+
return
61+
}
62+
63+
const current_checked = workspace_provider.get_checked_files()
64+
65+
let added = false
66+
if (!current_checked.includes(file_path)) {
67+
await workspace_provider.set_checked_files([
68+
...current_checked,
69+
file_path
70+
])
71+
added = true
72+
}
73+
74+
const open_button = 'Open File'
75+
76+
const message = added
77+
? `Added definition to context.`
78+
: `The definition is already in context.`
79+
80+
const selection = await vscode.window.showInformationMessage(
81+
message,
82+
open_button
83+
)
84+
85+
if (selection === open_button) {
86+
const doc = await vscode.workspace.openTextDocument(definition_uri)
87+
await vscode.window.showTextDocument(doc)
88+
}
89+
} catch (error) {
90+
vscode.window.showErrorMessage(
91+
`Check definition failed: ${
92+
error instanceof Error ? error.message : String(error)
93+
}`
94+
)
95+
Logger.error({
96+
function_name: 'check_definition_command',
97+
message: 'Error resolving definition',
98+
data: error
99+
})
100+
}
101+
}
102+
)
103+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import * as vscode from 'vscode'
2+
import * as path from 'path'
3+
import { WorkspaceProvider } from '../context/providers/workspace/workspace-provider'
4+
import { Logger } from '@shared/utils/logger'
5+
6+
export const check_references_command = (
7+
workspace_provider: WorkspaceProvider
8+
) => {
9+
return vscode.commands.registerCommand(
10+
'codeWebChat.checkReferences',
11+
async () => {
12+
const editor = vscode.window.activeTextEditor
13+
if (!editor) {
14+
return
15+
}
16+
17+
try {
18+
const document = editor.document
19+
const position = editor.selection.active
20+
21+
const matched_files = await vscode.window.withProgress(
22+
{
23+
location: vscode.ProgressLocation.Window,
24+
title: 'Searching for references...'
25+
},
26+
async () => {
27+
const locations = await vscode.commands.executeCommand<
28+
vscode.Location[]
29+
>('vscode.executeReferenceProvider', document.uri, position)
30+
31+
if (!locations) return []
32+
33+
const unique_paths = new Set<string>()
34+
locations.forEach((loc) => {
35+
const file_path = loc.uri.fsPath
36+
if (
37+
workspace_provider.get_workspace_root_for_file(file_path) &&
38+
!workspace_provider.is_ignored_by_patterns(file_path)
39+
) {
40+
unique_paths.add(file_path)
41+
}
42+
})
43+
return Array.from(unique_paths)
44+
}
45+
)
46+
47+
if (matched_files.length === 0) {
48+
vscode.window.showInformationMessage(
49+
'No files found referencing the current symbol.'
50+
)
51+
return
52+
}
53+
54+
const open_file_button = {
55+
iconPath: new vscode.ThemeIcon('go-to-file'),
56+
tooltip: 'Open file'
57+
}
58+
59+
const quick_pick_items = matched_files.map((file_path) => {
60+
const workspace_root =
61+
workspace_provider.get_workspace_root_for_file(file_path)
62+
const relative_path = workspace_root
63+
? path.relative(workspace_root, file_path)
64+
: file_path
65+
66+
const dir_name = path.dirname(relative_path)
67+
return {
68+
label: path.basename(file_path),
69+
description: dir_name == '.' ? '' : dir_name,
70+
file_path: file_path,
71+
buttons: [open_file_button]
72+
}
73+
})
74+
75+
const quick_pick = vscode.window.createQuickPick<
76+
vscode.QuickPickItem & { file_path: string }
77+
>()
78+
quick_pick.items = quick_pick_items
79+
quick_pick.selectedItems = quick_pick_items
80+
quick_pick.canSelectMany = true
81+
quick_pick.placeholder = 'Select files to check for context'
82+
quick_pick.title = `Found ${matched_files.length} file${
83+
matched_files.length == 1 ? '' : 's'
84+
}`
85+
quick_pick.ignoreFocusOut = true
86+
87+
const close_button = {
88+
iconPath: new vscode.ThemeIcon('close'),
89+
tooltip: 'Close'
90+
}
91+
quick_pick.buttons = [close_button]
92+
93+
const selected_items = await new Promise<
94+
readonly (vscode.QuickPickItem & { file_path: string })[] | undefined
95+
>((resolve) => {
96+
let is_accepted = false
97+
98+
quick_pick.onDidTriggerButton((button) => {
99+
if (button === close_button) {
100+
resolve(undefined)
101+
quick_pick.hide()
102+
}
103+
})
104+
105+
quick_pick.onDidAccept(() => {
106+
is_accepted = true
107+
resolve(quick_pick.selectedItems)
108+
quick_pick.hide()
109+
})
110+
111+
quick_pick.onDidHide(() => {
112+
if (!is_accepted) {
113+
resolve(undefined)
114+
}
115+
quick_pick.dispose()
116+
})
117+
118+
quick_pick.onDidTriggerItemButton(async (e) => {
119+
if (e.button === open_file_button) {
120+
try {
121+
const doc = await vscode.workspace.openTextDocument(
122+
e.item.file_path
123+
)
124+
await vscode.window.showTextDocument(doc, {
125+
preview: true
126+
})
127+
} catch (error) {
128+
vscode.window.showErrorMessage(`Error opening file: ${error}`)
129+
}
130+
}
131+
})
132+
133+
quick_pick.show()
134+
})
135+
136+
if (!selected_items || selected_items.length == 0) {
137+
return
138+
}
139+
140+
const selected_paths = selected_items.map((item) => item.file_path)
141+
const currently_checked = workspace_provider.get_checked_files()
142+
143+
const selected_paths_set = new Set(selected_paths)
144+
const unselected_files_set = new Set(
145+
matched_files.filter((file) => !selected_paths_set.has(file))
146+
)
147+
const currently_checked_filtered = currently_checked.filter(
148+
(file) => !unselected_files_set.has(file)
149+
)
150+
const paths_to_apply = [
151+
...new Set([...currently_checked_filtered, ...selected_paths])
152+
]
153+
154+
Logger.info({
155+
message: `Selected ${selected_paths.length} files from reference search.`,
156+
data: { paths: selected_paths }
157+
})
158+
159+
await workspace_provider.set_checked_files(paths_to_apply)
160+
vscode.window.showInformationMessage(`Context updated.`)
161+
} catch (error) {
162+
vscode.window.showErrorMessage(
163+
`Reference check failed: ${
164+
error instanceof Error ? error.message : String(error)
165+
}`
166+
)
167+
Logger.error({
168+
function_name: 'check_references_command',
169+
message: 'Error searching references',
170+
data: error
171+
})
172+
}
173+
}
174+
)
175+
}

‎apps/editor/src/commands/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ export * from './set-range-command'
2020
export * from './check-parent-folder-command'
2121
export * from './uncheck-parent-folder-command'
2222
export * from './check-all-with-keywords'
23+
export * from './check-references-command'
24+
export * from './check-definition-command'

‎apps/editor/src/extension.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import {
3333
set_range_command,
3434
check_parent_folder_command,
3535
uncheck_parent_folder_command,
36-
check_all_with_keywords_command
36+
check_all_with_keywords_command,
37+
check_references_command,
38+
check_definition_command
3739
} from './commands'
3840
import {
3941
get_checkpoints,
@@ -135,7 +137,9 @@ export async function activate(context: vscode.ExtensionContext) {
135137
check_parent_folder_command(workspace_provider),
136138
uncheck_parent_folder_command(workspace_provider),
137139
duplicate_workspace_command(workspace_provider, context),
140+
check_references_command(workspace_provider),
138141
check_all_with_keywords_command(workspace_provider, context),
142+
check_definition_command(workspace_provider),
139143
open_url_command({
140144
command: 'codeWebChat.openRepository',
141145
url: 'https://github.com/robertpiosik/CodeWebChat'

0 commit comments

Comments
 (0)