Skip to content

Commit ec0c626

Browse files
committed
Add an interactive format selection option for copying file paths
- to 'copy paths format' add new default, first on the list option: 'Ask' (when asking, remember last chosen option and highlight it on next command use) - rename translation keys (file name etc) to use command name 'copy paths' - move t('command.copy-context.warning.no-files-selected') to common - in `apps/editor/src/commands/copy-paths-command.ts` use static order of items, add close button and add appropriate translations - instead of 'recently used' description, use highlight └── apps └── editor ├── package.json └── src ├── commands │ ├── copy-markdown-command.ts │ ├── copy-paths-command.ts │ ├── new-file-command.ts │ ├── new-folder-command.ts │ ├── select-clipboard-paths-command.ts │ └── select-commit-files-command.ts ├── constants │ └── state-keys.ts ├── extension.ts ├── i18n │ ├── index.ts │ └── translations │ ├── commands │ │ ├── copy-paths.ts │ │ └── index.ts │ └── common.ts ├── utils │ └── extract-paths-from-text │ └── extract-paths-from-text.spec.ts └── views └── settings ├── backend │ ├── message-handlers │ │ ├── handle-get-copy-paths-format.ts │ │ └── handle-update-copy-paths-format.ts │ └── settings-view-provider.ts ├── frontend │ ├── Home │ │ ├── Home.tsx │ │ └── sections │ │ └── GeneralSection.tsx │ ├── Settings.tsx │ ├── hooks │ │ └── use-settings.ts │ └── i18n │ └── translations │ └── general.ts └── types └── messages.ts
1 parent df4b714 commit ec0c626

17 files changed

Lines changed: 284 additions & 59 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ Install the [browser extension](https://github.com/robertpiosik/CodeWebChat/tree
177177

178178
### Copy
179179

180-
- `Copy Markdown` - Copy contents of selected files.
181-
- `Copy Markdown of Open Editors` - Copy contents of open editors.
182-
- `Copy Paths` - Copy paths of selected files.
183-
- `Copy Paths of Open Editors` - Copy paths of open editors.
180+
- `Copy Markdown` - Copy contents of the current file selection.
181+
- `Copy Markdown of Open Editors` - Copy contents of file selection in open editors.
182+
- `Copy Paths` - Copy paths of the current file selection.
183+
- `Copy Paths of Open Editors` - Copy paths of file selection in open editors.
184184

185185
### Commit messages
186186

‎apps/editor/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,11 +994,12 @@
994994
"type": "string",
995995
"scope": "resource",
996996
"enum": [
997+
"ask",
997998
"bullet-list",
998999
"comma-separated",
9991000
"ascii-tree"
10001001
],
1001-
"default": "bullet-list"
1002+
"default": "ask"
10021003
},
10031004
"codeWebChat.sendWithShiftEnter": {
10041005
"type": "boolean",

‎apps/editor/src/commands/copy-markdown-command.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ export const copy_markdown_commands = (
3333
}
3434

3535
if (context_text == '') {
36-
vscode.window.showWarningMessage(
37-
t('command.copy-context.warning.no-files-selected')
38-
)
36+
vscode.window.showWarningMessage(t('common.warning.no-files-selected'))
3937
return
4038
}
4139

‎apps/editor/src/commands/copy-paths-command.ts‎

Lines changed: 107 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ import { t } from '../i18n'
55
import { WorkspaceProvider } from '../context/providers/workspace/workspace-provider'
66
import { OpenEditorsProvider } from '../context/providers/open-editors/open-editors-provider'
77
import { AsciiTree } from '../utils/ascii-tree'
8+
import { LAST_COPY_PATHS_FORMAT_STATE_KEY } from '../constants/state-keys'
89

9-
const format_paths = (files: string[]) => {
10-
const config = vscode.workspace.getConfiguration('codeWebChat')
11-
const format = config.get<'bullet-list' | 'comma-separated' | 'ascii-tree'>(
12-
'copyPathsFormat',
13-
'bullet-list'
14-
)
10+
type Format = 'bullet-list' | 'comma-separated' | 'ascii-tree'
1511

12+
const format_paths = (files: string[], format: Format) => {
1613
const workspace_folders = vscode.workspace.workspaceFolders
1714
const is_multi_root = !!workspace_folders && workspace_folders.length > 1
1815

@@ -43,24 +40,116 @@ const format_paths = (files: string[]) => {
4340
return display_paths.map((display_path) => `- \`${display_path}\``).join('\n')
4441
}
4542

43+
const resolve_format = async (
44+
extension_context: vscode.ExtensionContext
45+
): Promise<Format | undefined> => {
46+
const config = vscode.workspace.getConfiguration('codeWebChat')
47+
const configured_format = config.get<
48+
'ask' | 'bullet-list' | 'comma-separated' | 'ascii-tree'
49+
>('copyPathsFormat', 'ask')
50+
51+
if (configured_format != 'ask') {
52+
return configured_format as Format
53+
}
54+
55+
const last_format = extension_context.globalState.get<Format>(
56+
LAST_COPY_PATHS_FORMAT_STATE_KEY
57+
)
58+
59+
type Option = vscode.QuickPickItem & { value: Format }
60+
61+
const options: Option[] = [
62+
{
63+
label: t('command.copy-paths.format.bullet-list'),
64+
value: 'bullet-list'
65+
},
66+
{
67+
label: t('command.copy-paths.format.comma-separated'),
68+
value: 'comma-separated'
69+
},
70+
{
71+
label: t('command.copy-paths.format.ascii-tree'),
72+
value: 'ascii-tree'
73+
}
74+
]
75+
76+
const quick_pick = vscode.window.createQuickPick<Option>()
77+
quick_pick.title = t('command.copy-paths.title')
78+
quick_pick.placeholder = t('command.copy-paths.placeholder')
79+
quick_pick.items = options
80+
quick_pick.ignoreFocusOut = true
81+
82+
if (last_format) {
83+
const last_option = options.find((o) => o.value === last_format)
84+
if (last_option) {
85+
quick_pick.activeItems = [last_option]
86+
}
87+
}
88+
89+
const close_button = {
90+
iconPath: new vscode.ThemeIcon('close'),
91+
tooltip: t('common.close')
92+
}
93+
94+
quick_pick.buttons = [close_button]
95+
96+
const selected = await new Promise<Option | undefined>((resolve) => {
97+
let is_accepted = false
98+
99+
quick_pick.onDidTriggerButton((button) => {
100+
if (button === close_button) {
101+
resolve(undefined)
102+
quick_pick.hide()
103+
}
104+
})
105+
106+
quick_pick.onDidAccept(() => {
107+
is_accepted = true
108+
resolve(quick_pick.selectedItems[0])
109+
quick_pick.hide()
110+
})
111+
112+
quick_pick.onDidHide(() => {
113+
if (!is_accepted) {
114+
resolve(undefined)
115+
}
116+
quick_pick.dispose()
117+
})
118+
119+
quick_pick.show()
120+
})
121+
122+
if (selected) {
123+
await extension_context.globalState.update(
124+
LAST_COPY_PATHS_FORMAT_STATE_KEY,
125+
selected.value
126+
)
127+
return selected.value
128+
}
129+
130+
return undefined
131+
}
132+
46133
export const copy_paths_commands = (
47134
workspace_provider: WorkspaceProvider,
48-
open_editors_provider: OpenEditorsProvider
135+
open_editors_provider: OpenEditorsProvider,
136+
extension_context: vscode.ExtensionContext
49137
) => {
50138
return [
51139
vscode.commands.registerCommand('codeWebChat.copyPaths', async () => {
52140
const checked_files = workspace_provider.get_checked_files()
53141

54142
if (checked_files.length == 0) {
55-
vscode.window.showWarningMessage(
56-
t('command.copy-context.warning.no-files-selected')
57-
)
143+
vscode.window.showWarningMessage(t('common.warning.no-files-selected'))
58144
return
59145
}
60146

61-
const paths_text = format_paths(checked_files)
147+
const format = await resolve_format(extension_context)
148+
if (!format) return
149+
150+
const paths_text = format_paths(checked_files, format)
62151
await vscode.env.clipboard.writeText(paths_text)
63-
vscode.window.showInformationMessage('Paths copied to clipboard.')
152+
vscode.window.showInformationMessage(t('command.copy-paths.copied'))
64153
}),
65154

66155
vscode.commands.registerCommand(
@@ -71,14 +160,17 @@ export const copy_paths_commands = (
71160

72161
if (checked_files.length == 0) {
73162
vscode.window.showWarningMessage(
74-
dictionary.warning_message.NO_OPEN_EDITORS_SELECTED
163+
t('common.warning.no-files-selected')
75164
)
76165
return
77166
}
78167

79-
const paths_text = format_paths(checked_files)
168+
const format = await resolve_format(extension_context)
169+
if (!format) return
170+
171+
const paths_text = format_paths(checked_files, format)
80172
await vscode.env.clipboard.writeText(paths_text)
81-
vscode.window.showInformationMessage('Paths copied to clipboard.')
173+
vscode.window.showInformationMessage(t('command.copy-paths.copied'))
82174
}
83175
)
84176
]

‎apps/editor/src/constants/state-keys.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export const LAST_FIND_RELEVANT_FILES_SHRINK_STATE_KEY =
109109
'last-find-relevant-files-shrink'
110110

111111
export const LAST_ATTACH_ASCII_TREE_STATE_KEY = 'last-attach-ascii-tree'
112+
export const LAST_COPY_PATHS_FORMAT_STATE_KEY = 'last-copy-paths-format'
112113

113114
export type DuplicateWorkspaceContext = {
114115
checked_files: string[]

‎apps/editor/src/extension.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ export const activate = async (extension_context: vscode.ExtensionContext) => {
144144

145145
extension_context.subscriptions.push(
146146
...copy_markdown_commands(workspace_provider, open_editors_provider),
147-
...copy_paths_commands(workspace_provider, open_editors_provider),
147+
...copy_paths_commands(
148+
workspace_provider,
149+
open_editors_provider,
150+
extension_context
151+
),
148152
open_file_from_workspace_command(open_editors_provider),
149153
close_editor_command(),
150154
close_all_editors_command(),

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as vscode from 'vscode'
22
import { translations as commands } from './translations/commands'
33
import { translations as common } from './translations/common'
4-
import { translations as commands_copy_context } from './translations/commands/copy-context'
54
import { translations as views_settings_handlers_open_allow_patterns_settings } from './translations/views/settings/handlers/open-allow-patterns-settings'
65
import { translations as views_settings_handlers_open_ignore_patterns_settings } from './translations/views/settings/handlers/open-ignore-patterns-settings'
76
import { translations as views_settings_handlers_select_default_api_configuration } from './translations/views/settings/handlers/select-default-api-configuration'
@@ -29,7 +28,6 @@ export type TranslationKey = keyof typeof translations
2928

3029
const translations = {
3130
...commands,
32-
...commands_copy_context,
3331
...common,
3432
...views_settings_handlers_open_allow_patterns_settings,
3533
...views_settings_handlers_open_ignore_patterns_settings,

‎apps/editor/src/i18n/translations/commands/copy-context.ts‎

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
export const translations = {
2+
'command.copy-paths.title': {
3+
en: 'Copy Paths',
4+
pl: 'Kopiuj ścieżki',
5+
'zh-cn': '复制路径',
6+
ja: 'パスをコピー',
7+
'zh-tw': '複製路徑',
8+
de: 'Pfade kopieren',
9+
es: 'Copiar rutas',
10+
fr: 'Copier les chemins',
11+
'pt-br': 'Copiar caminhos',
12+
ru: 'Копировать пути',
13+
ko: '경로 복사',
14+
it: 'Copia percorsi',
15+
tr: 'Yolları Kopyala',
16+
cs: 'Kopírovat cesty',
17+
hu: 'Útvonalak másolása',
18+
bg: 'Копиране на пътища'
19+
},
20+
'command.copy-paths.placeholder': {
21+
en: 'Select a format to copy paths',
22+
pl: 'Wybierz format kopiowania ścieżek',
23+
'zh-cn': '选择复制路径的格式',
24+
ja: 'パスをコピーする形式を選択',
25+
'zh-tw': '選擇複製路徑的格式',
26+
de: 'Format zum Kopieren von Pfaden auswählen',
27+
es: 'Selecciona un formato para copiar rutas',
28+
fr: 'Sélectionner un format pour copier les chemins',
29+
'pt-br': 'Selecione um formato para copiar caminhos',
30+
ru: 'Выберите формат копирования путей',
31+
ko: '경로를 복사할 형식 선택',
32+
it: 'Seleziona un formato per copiare i percorsi',
33+
tr: 'Yolları kopyalamak için bir biçim seç',
34+
cs: 'Vyberte formát pro kopírování cest',
35+
hu: 'Válasszon formátumot az útvonalak másolásához',
36+
bg: 'Изберете формат за копиране на пътища'
37+
},
38+
'command.copy-paths.format.bullet-list': {
39+
en: 'Bullet List',
40+
pl: 'Lista punktowana',
41+
'zh-cn': '项目符号列表',
42+
ja: '箇条書きリスト',
43+
'zh-tw': '項目符號清單',
44+
de: 'Aufzählungsliste',
45+
es: 'Lista de viñetas',
46+
fr: 'Liste à puces',
47+
'pt-br': 'Lista com marcadores',
48+
ru: 'Маркированный список',
49+
ko: '글머리 기호 목록',
50+
it: 'Elenco puntato',
51+
tr: 'Madde İşaretli Liste',
52+
cs: 'Odrážkový seznam',
53+
hu: 'Felsorolásos lista',
54+
bg: 'Списък с водещи символи'
55+
},
56+
'command.copy-paths.format.comma-separated': {
57+
en: 'Comma-separated',
58+
pl: 'Oddzielone przecinkami',
59+
'zh-cn': '逗号分隔',
60+
ja: 'カンマ区切り',
61+
'zh-tw': '逗號分隔',
62+
de: 'Kommagetrennt',
63+
es: 'Separado por comas',
64+
fr: 'Séparé par des virgules',
65+
'pt-br': 'Separado por vírgulas',
66+
ru: 'Через запятую',
67+
ko: '쉼표로 구분',
68+
it: 'Separato da virgole',
69+
tr: 'Virgülle ayrılmış',
70+
cs: 'Oddělené čárkami',
71+
hu: 'Vesszővel elválasztva',
72+
bg: 'Разделени със запетая'
73+
},
74+
'command.copy-paths.format.ascii-tree': {
75+
en: 'ASCII Tree',
76+
pl: 'Drzewo ASCII',
77+
'zh-cn': 'ASCII 树',
78+
ja: 'ASCII ツリー',
79+
'zh-tw': 'ASCII 樹',
80+
de: 'ASCII-Baum',
81+
es: 'Árbol ASCII',
82+
fr: 'Arbre ASCII',
83+
'pt-br': 'Árvore ASCII',
84+
ru: 'ASCII-дерево',
85+
ko: 'ASCII 트리',
86+
it: 'Albero ASCII',
87+
tr: 'ASCII Ağacı',
88+
cs: 'ASCII Strom',
89+
hu: 'ASCII Fa',
90+
bg: 'ASCII дърво'
91+
},
92+
'command.copy-paths.copied': {
93+
en: 'Paths copied to clipboard.',
94+
pl: 'Ścieżki skopiowane do schowka.',
95+
'zh-cn': '路径已复制到剪贴板。',
96+
ja: 'パスがクリップボードにコピーされました。',
97+
'zh-tw': '路徑已複製到剪貼簿。',
98+
de: 'Pfade in die Zwischenablage kopiert.',
99+
es: 'Rutas copiadas al portapapeles.',
100+
fr: 'Chemins copiés dans le presse-papiers.',
101+
'pt-br': 'Caminhos copiados para a área de transferência.',
102+
ru: 'Пути скопированы в буфер обмена.',
103+
ko: '경로가 클립보드에 복사되었습니다.',
104+
it: 'Percorsi copiati negli appunti.',
105+
tr: 'Yollar panoya kopyalandı.',
106+
cs: 'Cesty zkopírovány do schránky.',
107+
hu: 'Útvonalak a vágólapra másolva.',
108+
bg: 'Пътищата са копирани в клипборда.'
109+
}
110+
} as const

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { translations as select_changed_files } from './select-changed-files'
1818
import { translations as history } from './history'
1919
import { translations as select_clipboard_paths } from './select-clipboard-paths'
2020
import { translations as select_imported_files } from './select-imported-files'
21+
import { translations as copy_paths } from './copy-paths'
2122

2223
export const translations = {
2324
...generate_commit_message,
@@ -39,5 +40,6 @@ export const translations = {
3940
...select_changed_files,
4041
...history,
4142
...select_clipboard_paths,
42-
...select_imported_files
43+
...select_imported_files,
44+
...copy_paths
4345
}

0 commit comments

Comments
 (0)