Skip to content

Commit 06dcf2e

Browse files
author
Cosm1cAC
committed
fix(windows): read search_code temp files as UTF-8
Signed-off-by: Cosm1cAC <cosm1cac@github.com>
1 parent b637e33 commit 06dcf2e

2 files changed

Lines changed: 80 additions & 6 deletions

File tree

src/mcp/mcp.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4496,17 +4496,17 @@ static void build_grep_cmd(char *cmd, size_t cmd_sz, bool use_regex, bool scoped
44964496
if (file_pattern) {
44974497
snprintf(
44984498
cmd, cmd_sz,
4499-
"powershell -Command \"$pat = Get-Content '%s'; "
4500-
"Get-Content '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
4499+
"powershell -Command \"$pat = Get-Content -Encoding UTF8 -LiteralPath '%s'; "
4500+
"Get-Content -Encoding UTF8 -LiteralPath '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
45014501
"-ErrorAction SilentlyContinue }"
45024502
" | Where-Object { $_.Path -like '*%s' }"
45034503
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
45044504
tmpfile, filelist, sm, file_pattern);
45054505
} else {
45064506
snprintf(
45074507
cmd, cmd_sz,
4508-
"powershell -Command \"$pat = Get-Content '%s'; "
4509-
"Get-Content '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
4508+
"powershell -Command \"$pat = Get-Content -Encoding UTF8 -LiteralPath '%s'; "
4509+
"Get-Content -Encoding UTF8 -LiteralPath '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
45104510
"-ErrorAction SilentlyContinue }"
45114511
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
45124512
tmpfile, filelist, sm);
@@ -4517,15 +4517,15 @@ static void build_grep_cmd(char *cmd, size_t cmd_sz, bool use_regex, bool scoped
45174517
cmd, cmd_sz,
45184518
"powershell -Command \"Get-ChildItem -Recurse -Path '%s\\*' -Include '%s' -File "
45194519
"-ErrorAction SilentlyContinue"
4520-
" | Select-String -Pattern (Get-Content '%s')%s -ErrorAction SilentlyContinue"
4520+
" | Select-String -Pattern (Get-Content -Encoding UTF8 -LiteralPath '%s')%s -ErrorAction SilentlyContinue"
45214521
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
45224522
root_path, file_pattern, tmpfile, sm);
45234523
} else {
45244524
snprintf(
45254525
cmd, cmd_sz,
45264526
"powershell -Command \"Get-ChildItem -Recurse -Path '%s\\*' -File -ErrorAction "
45274527
"SilentlyContinue"
4528-
" | Select-String -Pattern (Get-Content '%s')%s -ErrorAction SilentlyContinue"
4528+
" | Select-String -Pattern (Get-Content -Encoding UTF8 -LiteralPath '%s')%s -ErrorAction SilentlyContinue"
45294529
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
45304530
root_path, tmpfile, sm);
45314531
}

tests/test_mcp.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,6 +1755,77 @@ TEST(search_code_scoped_path_with_spaces_issue687) {
17551755
PASS();
17561756
}
17571757

1758+
#ifdef _WIN32
1759+
/* Issue #903 follow-up: scoped search_code on Windows writes a UTF-8 filelist
1760+
* containing absolute source paths, then reads it back through PowerShell.
1761+
* Windows PowerShell 5.1 treats UTF-8 without BOM as ANSI unless told
1762+
* otherwise, so a non-ASCII project root can be mojibaked before
1763+
* Select-String sees the LiteralPath. */
1764+
TEST(search_code_scoped_path_with_cjk_root_issue903) {
1765+
char tmp[512];
1766+
snprintf(tmp, sizeof(tmp), "%s/cbm_srch_cjk_XXXXXX", cbm_tmpdir());
1767+
if (!cbm_mkdtemp(tmp)) {
1768+
FAIL("cbm_mkdtemp failed");
1769+
}
1770+
1771+
char proj_dir[640];
1772+
snprintf(proj_dir, sizeof(proj_dir), "%s/%s", tmp,
1773+
"\xE4\xB8\xAD\xE6\x96\x87\xE9\xA1\xB9\xE7\x9B\xAE");
1774+
cbm_mkdir(proj_dir);
1775+
1776+
char src_path[768];
1777+
snprintf(src_path, sizeof(src_path), "%s/main.go", proj_dir);
1778+
FILE *fp = cbm_fopen(src_path, "wb");
1779+
if (!fp) {
1780+
cbm_rmdir(proj_dir);
1781+
cbm_rmdir(tmp);
1782+
FAIL("cannot write source file under CJK path");
1783+
}
1784+
fprintf(fp, "package main\n\nfunc HandleRequest() error {\n\treturn nil\n}\n");
1785+
fclose(fp);
1786+
1787+
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
1788+
ASSERT_NOT_NULL(srv);
1789+
cbm_store_t *st = cbm_mcp_server_store(srv);
1790+
ASSERT_NOT_NULL(st);
1791+
const char *proj = "cjk-search";
1792+
cbm_mcp_server_set_project(srv, proj);
1793+
cbm_store_upsert_project(st, proj, proj_dir);
1794+
1795+
cbm_node_t n = {.project = proj,
1796+
.label = "Function",
1797+
.name = "HandleRequest",
1798+
.qualified_name = "cjk-search.main.HandleRequest",
1799+
.file_path = "main.go",
1800+
.start_line = 3,
1801+
.end_line = 5};
1802+
ASSERT_GT(cbm_store_upsert_node(st, &n), 0);
1803+
1804+
char *resp = cbm_mcp_server_handle(
1805+
srv, "{\"jsonrpc\":\"2.0\",\"id\":903,\"method\":\"tools/call\","
1806+
"\"params\":{\"name\":\"search_code\","
1807+
"\"arguments\":{\"pattern\":\"HandleRequest\",\"project\":\"cjk-search\"}}}");
1808+
ASSERT_NOT_NULL(resp);
1809+
char *inner = extract_text_content(resp);
1810+
ASSERT_NOT_NULL(inner);
1811+
1812+
int grep_matches = -1;
1813+
const char *g = strstr(inner, "\"total_grep_matches\":");
1814+
if (g) {
1815+
sscanf(g, "\"total_grep_matches\":%d", &grep_matches);
1816+
}
1817+
ASSERT_TRUE(grep_matches > 0);
1818+
1819+
free(inner);
1820+
free(resp);
1821+
cbm_mcp_server_free(srv);
1822+
cbm_unlink(src_path);
1823+
cbm_rmdir(proj_dir);
1824+
cbm_rmdir(tmp);
1825+
PASS();
1826+
}
1827+
#endif
1828+
17581829
/* Shared fixture for the path_filter prefilter tests (PR #756 distilled):
17591830
* a project with two indexed files that both contain the search pattern —
17601831
* src/handler.go (inside the filter) and vendor/other.go (outside it). */
@@ -5072,6 +5143,9 @@ SUITE(mcp) {
50725143
RUN_TEST(tool_search_code_no_project);
50735144
RUN_TEST(search_code_multi_word);
50745145
RUN_TEST(search_code_scoped_path_with_spaces_issue687);
5146+
#ifdef _WIN32
5147+
RUN_TEST(search_code_scoped_path_with_cjk_root_issue903);
5148+
#endif
50755149
RUN_TEST(search_code_path_filter_prefilter_keeps_matches);
50765150
RUN_TEST(search_code_path_filter_matches_nothing);
50775151
RUN_TEST(search_code_invalid_regex_errors_issue283);

0 commit comments

Comments
 (0)