Skip to content

Commit 305185c

Browse files
KJ7LNWEric Wheeler
andauthored
feat: clickable code references in model responses navigate to source lines (#3087)
Co-authored-by: Eric Wheeler <[email protected]>
1 parent 01fec4c commit 305185c

File tree

7 files changed

+141
-6
lines changed

7 files changed

+141
-6
lines changed

src/core/prompts/__tests__/__snapshots__/system.test.ts.snap

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ exports[`SYSTEM_PROMPT should exclude diff strategy tool description when diffEn
55
66
====
77
8+
MARKDOWN RULES
9+
10+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
11+
12+
====
13+
814
TOOL USE
915
1016
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -472,6 +478,12 @@ exports[`SYSTEM_PROMPT should exclude diff strategy tool description when diffEn
472478
473479
====
474480
481+
MARKDOWN RULES
482+
483+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
484+
485+
====
486+
475487
TOOL USE
476488
477489
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -939,6 +951,12 @@ exports[`SYSTEM_PROMPT should explicitly handle undefined mcpHub 1`] = `
939951
940952
====
941953
954+
MARKDOWN RULES
955+
956+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
957+
958+
====
959+
942960
TOOL USE
943961
944962
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -1406,6 +1424,12 @@ exports[`SYSTEM_PROMPT should handle different browser viewport sizes 1`] = `
14061424
14071425
====
14081426
1427+
MARKDOWN RULES
1428+
1429+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
1430+
1431+
====
1432+
14091433
TOOL USE
14101434
14111435
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -1929,6 +1953,12 @@ exports[`SYSTEM_PROMPT should include MCP server info when mcpHub is provided 1`
19291953
19301954
====
19311955
1956+
MARKDOWN RULES
1957+
1958+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
1959+
1960+
====
1961+
19321962
TOOL USE
19331963
19341964
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -2464,6 +2494,12 @@ exports[`SYSTEM_PROMPT should include browser actions when supportsComputerUse i
24642494
24652495
====
24662496
2497+
MARKDOWN RULES
2498+
2499+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
2500+
2501+
====
2502+
24672503
TOOL USE
24682504
24692505
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -2987,6 +3023,12 @@ exports[`SYSTEM_PROMPT should include diff strategy tool description when diffEn
29873023
29883024
====
29893025
3026+
MARKDOWN RULES
3027+
3028+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
3029+
3030+
====
3031+
29903032
TOOL USE
29913033
29923034
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -3544,6 +3586,12 @@ exports[`SYSTEM_PROMPT should maintain consistent system prompt 1`] = `
35443586
35453587
====
35463588
3589+
MARKDOWN RULES
3590+
3591+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
3592+
3593+
====
3594+
35473595
TOOL USE
35483596
35493597
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -4053,6 +4101,12 @@ exports[`addCustomInstructions should exclude MCP server creation info when disa
40534101
40544102
====
40554103
4104+
MARKDOWN RULES
4105+
4106+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
4107+
4108+
====
4109+
40564110
TOOL USE
40574111
40584112
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -4597,6 +4651,12 @@ exports[`addCustomInstructions should generate correct prompt for architect mode
45974651
45984652
====
45994653
4654+
MARKDOWN RULES
4655+
4656+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
4657+
4658+
====
4659+
46004660
TOOL USE
46014661
46024662
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -5055,6 +5115,12 @@ exports[`addCustomInstructions should generate correct prompt for ask mode 1`] =
50555115
50565116
====
50575117
5118+
MARKDOWN RULES
5119+
5120+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
5121+
5122+
====
5123+
50585124
TOOL USE
50595125
50605126
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@@ -5430,6 +5496,12 @@ exports[`addCustomInstructions should include MCP server creation info when enab
54305496
54315497
====
54325498
5499+
MARKDOWN RULES
5500+
5501+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>
5502+
5503+
====
5504+
54335505
TOOL USE
54345506
54355507
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.

src/core/prompts/sections/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { getMcpServersSection } from "./mcp-servers"
77
export { getToolUseGuidelinesSection } from "./tool-use-guidelines"
88
export { getCapabilitiesSection } from "./capabilities"
99
export { getModesSection } from "./modes"
10+
export { markdownFormattingSection } from "./markdown-formatting"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function markdownFormattingSection(): string {
2+
return `====
3+
4+
MARKDOWN RULES
5+
6+
ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in <attempt_completion>`
7+
}

src/core/prompts/system.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
getCapabilitiesSection,
2525
getModesSection,
2626
addCustomInstructions,
27+
markdownFormattingSection,
2728
} from "./sections"
2829
import { loadSystemPromptFile } from "./sections/custom-system-prompt"
2930
import { formatLanguage } from "../../shared/language"
@@ -65,6 +66,8 @@ async function generatePrompt(
6566

6667
const basePrompt = `${roleDefinition}
6768
69+
${markdownFormattingSection()}
70+
6871
${getSharedToolUseSection()}
6972
7073
${getToolDescriptionsForMode(

src/core/webview/webviewMessageHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
336336
openImage(message.text!)
337337
break
338338
case "openFile":
339-
openFile(message.text!, message.values as { create?: boolean; content?: string })
339+
openFile(message.text!, message.values as { create?: boolean; content?: string; line?: number })
340340
break
341341
case "openMention":
342342
openMention(message.text)

src/integrations/misc/open-file.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export async function openImage(dataUri: string) {
2323
interface OpenFileOptions {
2424
create?: boolean
2525
content?: string
26+
line?: number
2627
}
2728

2829
export async function openFile(filePath: string, options: OpenFileOptions = {}) {
@@ -75,7 +76,12 @@ export async function openFile(filePath: string, options: OpenFileOptions = {})
7576
} catch {} // not essential, sometimes tab operations fail
7677

7778
const document = await vscode.workspace.openTextDocument(uri)
78-
await vscode.window.showTextDocument(document, { preview: false })
79+
const selection =
80+
options.line !== undefined ? new vscode.Selection(options.line - 1, 0, options.line - 1, 0) : undefined
81+
await vscode.window.showTextDocument(document, {
82+
preview: false,
83+
selection,
84+
})
7985
} catch (error) {
8086
if (error instanceof Error) {
8187
vscode.window.showErrorMessage(`Could not open file: ${error.message}`)

webview-ui/src/components/common/MarkdownBlock.tsx

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRemark } from "react-remark"
33
import styled from "styled-components"
44
import { visit } from "unist-util-visit"
55

6+
import { vscode } from "@src/utils/vscode"
67
import { useExtensionState } from "@src/context/ExtensionStateContext"
78

89
import CodeBlock from "./CodeBlock"
@@ -108,11 +109,14 @@ const StyledMarkdown = styled.div`
108109
}
109110
110111
a {
111-
text-decoration: none;
112-
}
113-
a {
112+
color: var(--vscode-textLink-foreground);
113+
text-decoration-line: underline;
114+
text-decoration-style: dotted;
115+
text-decoration-color: var(--vscode-textLink-foreground);
114116
&:hover {
115-
text-decoration: underline;
117+
color: var(--vscode-textLink-activeForeground);
118+
text-decoration-style: solid;
119+
text-decoration-color: var(--vscode-textLink-activeForeground);
116120
}
117121
}
118122
`
@@ -137,6 +141,48 @@ const MarkdownBlock = memo(({ markdown }: MarkdownBlockProps) => {
137141
rehypePlugins: [],
138142
rehypeReactOptions: {
139143
components: {
144+
a: ({ href, children }: any) => {
145+
return (
146+
<a
147+
href={href}
148+
title={href}
149+
onClick={(e) => {
150+
// Only process file:// protocol or local file paths
151+
const isLocalPath =
152+
href.startsWith("file://") || href.startsWith("/") || !href.includes("://")
153+
154+
if (!isLocalPath) {
155+
return
156+
}
157+
158+
e.preventDefault()
159+
160+
// Handle absolute vs project-relative paths
161+
let filePath = href.replace("file://", "")
162+
163+
// Extract line number if present
164+
const match = filePath.match(/(.*):(\d+)(-\d+)?$/)
165+
let values = undefined
166+
if (match) {
167+
filePath = match[1]
168+
values = { line: parseInt(match[2]) }
169+
}
170+
171+
// Add ./ prefix if needed
172+
if (!filePath.startsWith("/") && !filePath.startsWith("./")) {
173+
filePath = "./" + filePath
174+
}
175+
176+
vscode.postMessage({
177+
type: "openFile",
178+
text: filePath,
179+
values,
180+
})
181+
}}>
182+
{children}
183+
</a>
184+
)
185+
},
140186
pre: ({ node: _, children }: any) => {
141187
// Check for Mermaid diagrams first
142188
if (Array.isArray(children) && children.length === 1 && React.isValidElement(children[0])) {

0 commit comments

Comments
 (0)