forked from codinit-dev/codinit-dev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtoolMentionParser.ts
More file actions
121 lines (94 loc) · 3.37 KB
/
Copy pathtoolMentionParser.ts
File metadata and controls
121 lines (94 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
export interface AutocompleteState {
isOpen: boolean;
searchQuery: string;
atPosition: number;
}
export type ReferenceType = 'file' | 'tool';
export function shouldShowAutocomplete(text: string, cursorPos: number): AutocompleteState {
const textBeforeCursor = text.slice(0, cursorPos);
const lastAtIndex = textBeforeCursor.lastIndexOf('@');
if (lastAtIndex === -1) {
return { isOpen: false, searchQuery: '', atPosition: -1 };
}
const textAfterAt = textBeforeCursor.slice(lastAtIndex + 1);
if (textAfterAt.includes(' ')) {
return { isOpen: false, searchQuery: '', atPosition: -1 };
}
if (lastAtIndex > 0 && !/\s/.test(text[lastAtIndex - 1])) {
return { isOpen: false, searchQuery: '', atPosition: -1 };
}
return {
isOpen: true,
searchQuery: textAfterAt,
atPosition: lastAtIndex,
};
}
export function extractSearchQuery(text: string, cursorPos: number): string {
const state = shouldShowAutocomplete(text, cursorPos);
return state.searchQuery;
}
export function detectReferenceType(searchQuery: string): ReferenceType {
return /[\/\.]/.test(searchQuery) ? 'file' : 'tool';
}
function getTextWidth(text: string, font: string): number {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) {
return text.length * 8;
}
context.font = font;
return context.measureText(text).width;
}
export function calculateDropdownPosition(
textarea: HTMLTextAreaElement,
atPosition: number,
): { x: number; y: number } | null {
if (!textarea) {
return null;
}
const text = textarea.value.slice(0, atPosition);
const lines = text.split('\n');
const currentLine = lines.length - 1;
const textBeforeCursor = lines[lines.length - 1];
const style = window.getComputedStyle(textarea);
const fontSize = parseFloat(style.fontSize);
const lineHeight = parseFloat(style.lineHeight) || fontSize * 1.2;
const paddingLeft = parseFloat(style.paddingLeft);
const paddingTop = parseFloat(style.paddingTop);
const font = `${style.fontSize} ${style.fontFamily}`;
const textWidth = getTextWidth(textBeforeCursor, font);
const rect = textarea.getBoundingClientRect();
const x = rect.left + paddingLeft + textWidth - textarea.scrollLeft;
const y = rect.top + paddingTop + (currentLine + 1) * lineHeight;
return { x, y };
}
export function insertToolMention(
text: string,
cursorPos: number,
toolName: string,
): { newText: string; newCursorPos: number } {
const state = shouldShowAutocomplete(text, cursorPos);
if (!state.isOpen) {
return { newText: text, newCursorPos: cursorPos };
}
const beforeAt = text.slice(0, state.atPosition);
const afterCursor = text.slice(cursorPos);
const newText = `${beforeAt}@${toolName} ${afterCursor}`;
const newCursorPos = state.atPosition + toolName.length + 2;
return { newText, newCursorPos };
}
export function insertFileReference(
text: string,
cursorPos: number,
filePath: string,
): { newText: string; newCursorPos: number } {
const state = shouldShowAutocomplete(text, cursorPos);
if (!state.isOpen) {
return { newText: text, newCursorPos: cursorPos };
}
const beforeAt = text.slice(0, state.atPosition);
const afterCursor = text.slice(cursorPos);
const newText = `${beforeAt}@${filePath} ${afterCursor}`;
const newCursorPos = state.atPosition + filePath.length + 2;
return { newText, newCursorPos };
}