Skip to content

Commit 3e1ddc7

Browse files
committed
feat(context): add system context for shell command output
Adds a new 'system' context that allows including the output of shell commands in chat context. This feature is useful for incorporating system information or command results directly into Copilot Chat. The implementation: - Updates documentation in README.md - Adds new context entry in contexts.lua with input prompt - Implements M.cmd() function with cross-platform support - Adds status notifications for context operations Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
1 parent 1a31700 commit 3e1ddc7

6 files changed

Lines changed: 62 additions & 16 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ The mappings can be customized by setting the `mappings` table in your configura
180180

181181
- `normal`: Key for normal mode
182182
- `insert`: Key for insert mode
183-
- `detail`: Description of what the mapping does
184183

185184
For example, to change the submit prompt mapping or show_diff full diff option:
186185

@@ -323,6 +322,7 @@ Contexts provide additional information to the chat. Add context using `#context
323322
| `url` | ✓ (url) | Content from URL |
324323
| `register` | ✓ (name) | Content of vim register |
325324
| `quickfix` | - | Quickfix list file contents |
325+
| `system` | ✓ (command) | Output of shell command |
326326

327327
Examples:
328328

@@ -333,6 +333,7 @@ Examples:
333333
> #filenames
334334
> #git:staged
335335
> #url:https://example.com
336+
> #system:`ls -la | grep lua`
336337
```
337338

338339
Define your own contexts in the configuration with input handling and resolution:
@@ -575,7 +576,6 @@ Below are all available configuration options with their default values:
575576
insert = '<C-s>',
576577
},
577578
toggle_sticky = {
578-
detail = 'Makes line under cursor sticky or deletes sticky line.',
579579
normal = 'gr',
580580
},
581581
accept_diff = {

lua/CopilotChat/config/contexts.lua

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,18 @@ return {
172172
return context.quickfix()
173173
end,
174174
},
175+
176+
system = {
177+
description = 'Includes output of provided system shell command in chat context. Supports input.',
178+
input = function(callback)
179+
vim.ui.input({
180+
prompt = 'Enter command> ',
181+
}, callback)
182+
end,
183+
resolve = function(input)
184+
return {
185+
context.system(input),
186+
}
187+
end,
188+
},
175189
}

lua/CopilotChat/config/mappings.lua

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ end
9898
---@class CopilotChat.config.mapping
9999
---@field normal string?
100100
---@field insert string?
101-
---@field detail string?
102101
---@field callback fun(overlay: CopilotChat.ui.Overlay, diff: CopilotChat.ui.Diff, chat: CopilotChat.ui.Chat, source: CopilotChat.source)
103102

104103
---@class CopilotChat.config.mapping.yank_diff : CopilotChat.config.mapping
@@ -159,7 +158,6 @@ return {
159158
},
160159

161160
toggle_sticky = {
162-
detail = 'Makes line under cursor sticky or deletes sticky line.',
163161
normal = 'gr',
164162
callback = function(overlay, diff, chat)
165163
local section = chat:get_closest_section()

lua/CopilotChat/context.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ end
458458
---@param bufnr number
459459
---@return CopilotChat.context.embed?
460460
function M.buffer(bufnr)
461+
notify.publish(notify.STATUS, 'Reading buffer ' .. bufnr)
461462
utils.schedule_main()
462463

463464
if not utils.buf_valid(bufnr) then
@@ -593,6 +594,7 @@ end
593594
---@param register string
594595
---@return CopilotChat.context.embed?
595596
function M.register(register)
597+
notify.publish(notify.STATUS, 'Reading register ' .. register)
596598
utils.schedule_main()
597599

598600
local lines = vim.fn.getreg(register)
@@ -610,6 +612,7 @@ end
610612
--- Get the content of the quickfix list
611613
---@return table<CopilotChat.context.embed>
612614
function M.quickfix()
615+
notify.publish(notify.STATUS, 'Reading quickfix list')
613616
utils.schedule_main()
614617

615618
local items = vim.fn.getqflist()
@@ -647,6 +650,32 @@ function M.quickfix()
647650
return out
648651
end
649652

653+
--- Get the output of a system shell command
654+
---@param command string The command to execute
655+
---@return CopilotChat.context.embed?
656+
function M.system(command)
657+
notify.publish(notify.STATUS, 'Executing command: ' .. command)
658+
utils.schedule_main()
659+
660+
local shell, shell_flag
661+
if vim.fn.has('win32') == 1 then
662+
shell, shell_flag = 'cmd.exe', '/c'
663+
else
664+
shell, shell_flag = 'sh', '-c'
665+
end
666+
667+
local out = utils.system({ shell, shell_flag, command })
668+
if not out or out.stdout == '' then
669+
return nil
670+
end
671+
672+
return {
673+
content = out.stdout,
674+
filename = 'command_output_' .. command:gsub('[^%w]', '_'):sub(1, 20),
675+
filetype = 'text',
676+
}
677+
end
678+
650679
--- Filter embeddings based on the query
651680
---@param prompt string
652681
---@param model string

lua/CopilotChat/init.lua

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ local utils = require('CopilotChat.utils')
77
local M = {}
88
local PLUGIN_NAME = 'CopilotChat'
99
local WORD = '([^%s]+)'
10+
local WORD_INPUT = '([^%s:]+:`[^`]+`)'
1011

1112
--- @class CopilotChat.source
1213
--- @field bufnr number
@@ -260,6 +261,10 @@ function M.resolve_embeddings(prompt, config)
260261
local split = vim.split(prompt_context, ':')
261262
local context_name = table.remove(split, 1)
262263
local context_input = vim.trim(table.concat(split, ':'))
264+
if vim.startswith(context_input, '`') and vim.endswith(context_input, '`') then
265+
context_input = context_input:sub(2, -2)
266+
end
267+
263268
if M.config.contexts[context_name] then
264269
table.insert(contexts, {
265270
name = context_name,
@@ -272,11 +277,12 @@ function M.resolve_embeddings(prompt, config)
272277
return false
273278
end
274279

280+
prompt = prompt:gsub('#' .. WORD_INPUT, function(match)
281+
return parse_context(match) and '' or '#' .. match
282+
end)
283+
275284
prompt = prompt:gsub('#' .. WORD, function(match)
276-
if parse_context(match) then
277-
return ''
278-
end
279-
return '#' .. match
285+
return parse_context(match) and '' or '#' .. match
280286
end)
281287

282288
if config.context then
@@ -392,7 +398,11 @@ function M.trigger_complete(with_context)
392398
return
393399
end
394400

395-
local value_str = tostring(value)
401+
local value_str = vim.trim(tostring(value))
402+
if value_str:find('%s') then
403+
value_str = '`' .. value_str .. '`'
404+
end
405+
396406
vim.api.nvim_buf_set_text(bufnr, row - 1, col, row - 1, col, { value_str })
397407
vim.api.nvim_win_set_cursor(0, { row, col + #value_str })
398408
end, state.source or {})

lua/CopilotChat/utils.lua

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ end, 1)
480480

481481
--- Get the info for a key.
482482
---@param name string
483+
---@param key table
483484
---@param surround string|nil
484485
---@return string
485486
function M.key_to_info(name, key, surround)
@@ -502,13 +503,7 @@ function M.key_to_info(name, key, surround)
502503
return out
503504
end
504505

505-
out = out .. ' to ' .. name:gsub('_', ' ')
506-
507-
if key.detail and key.detail ~= '' then
508-
out = out .. '. ' .. key.detail
509-
end
510-
511-
return out
506+
return out .. ' to ' .. name:gsub('_', ' ')
512507
end
513508

514509
--- Check if a value is empty

0 commit comments

Comments
 (0)