Skip to content

Commit a70d39d

Browse files
authored
Merge pull request DeusData#956 from Cosm1cAC/fix/windows-search-code-utf8-paths
fix(windows): read search_code temp files as UTF-8
2 parents c3bee33 + 8e0c29a commit a70d39d

2 files changed

Lines changed: 87 additions & 6 deletions

File tree

‎src/mcp/mcp.c‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4804,17 +4804,19 @@ static void build_grep_cmd(char *cmd, size_t cmd_sz, bool use_regex, bool scoped
48044804
if (file_pattern) {
48054805
snprintf(
48064806
cmd, cmd_sz,
4807-
"powershell -Command \"$pat = Get-Content '%s'; "
4808-
"Get-Content '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
4807+
"powershell -Command \"$pat = Get-Content -Encoding UTF8 -LiteralPath '%s'; "
4808+
"Get-Content -Encoding UTF8 -LiteralPath '%s' | ForEach-Object { Select-String "
4809+
"-LiteralPath $_ -Pattern $pat%s "
48094810
"-ErrorAction SilentlyContinue }"
48104811
" | Where-Object { $_.Path -like '*%s' }"
48114812
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
48124813
tmpfile, filelist, sm, file_pattern);
48134814
} else {
48144815
snprintf(
48154816
cmd, cmd_sz,
4816-
"powershell -Command \"$pat = Get-Content '%s'; "
4817-
"Get-Content '%s' | ForEach-Object { Select-String -LiteralPath $_ -Pattern $pat%s "
4817+
"powershell -Command \"$pat = Get-Content -Encoding UTF8 -LiteralPath '%s'; "
4818+
"Get-Content -Encoding UTF8 -LiteralPath '%s' | ForEach-Object { Select-String "
4819+
"-LiteralPath $_ -Pattern $pat%s "
48184820
"-ErrorAction SilentlyContinue }"
48194821
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
48204822
tmpfile, filelist, sm);
@@ -4825,15 +4827,17 @@ static void build_grep_cmd(char *cmd, size_t cmd_sz, bool use_regex, bool scoped
48254827
cmd, cmd_sz,
48264828
"powershell -Command \"Get-ChildItem -Recurse -Path '%s\\*' -Include '%s' -File "
48274829
"-ErrorAction SilentlyContinue"
4828-
" | Select-String -Pattern (Get-Content '%s')%s -ErrorAction SilentlyContinue"
4830+
" | Select-String -Pattern (Get-Content -Encoding UTF8 -LiteralPath '%s')%s "
4831+
"-ErrorAction SilentlyContinue"
48294832
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
48304833
root_path, file_pattern, tmpfile, sm);
48314834
} else {
48324835
snprintf(
48334836
cmd, cmd_sz,
48344837
"powershell -Command \"Get-ChildItem -Recurse -Path '%s\\*' -File -ErrorAction "
48354838
"SilentlyContinue"
4836-
" | Select-String -Pattern (Get-Content '%s')%s -ErrorAction SilentlyContinue"
4839+
" | Select-String -Pattern (Get-Content -Encoding UTF8 -LiteralPath '%s')%s "
4840+
"-ErrorAction SilentlyContinue"
48374841
" | ForEach-Object { $_.Path + [char]9 + $_.LineNumber + [char]9 + $_.Line }\"",
48384842
root_path, tmpfile, sm);
48394843
}

‎tests/test_mcp.c‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,6 +1755,80 @@ 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+
if (!cbm_mkdir_p(proj_dir, 0755)) {
1775+
cbm_rmdir(tmp);
1776+
FAIL("cannot create CJK project dir");
1777+
}
1778+
1779+
char src_path[768];
1780+
snprintf(src_path, sizeof(src_path), "%s/main.go", proj_dir);
1781+
FILE *fp = cbm_fopen(src_path, "wb");
1782+
if (!fp) {
1783+
cbm_rmdir(proj_dir);
1784+
cbm_rmdir(tmp);
1785+
FAIL("cannot write source file under CJK path");
1786+
}
1787+
fprintf(fp, "package main\n\nfunc HandleRequest() error {\n\treturn nil\n}\n");
1788+
fclose(fp);
1789+
1790+
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
1791+
ASSERT_NOT_NULL(srv);
1792+
cbm_store_t *st = cbm_mcp_server_store(srv);
1793+
ASSERT_NOT_NULL(st);
1794+
const char *proj = "cjk-search";
1795+
cbm_mcp_server_set_project(srv, proj);
1796+
cbm_store_upsert_project(st, proj, proj_dir);
1797+
1798+
cbm_node_t n = {.project = proj,
1799+
.label = "Function",
1800+
.name = "HandleRequest",
1801+
.qualified_name = "cjk-search.main.HandleRequest",
1802+
.file_path = "main.go",
1803+
.start_line = 3,
1804+
.end_line = 5};
1805+
ASSERT_GT(cbm_store_upsert_node(st, &n), 0);
1806+
1807+
char *resp = cbm_mcp_server_handle(
1808+
srv, "{\"jsonrpc\":\"2.0\",\"id\":903,\"method\":\"tools/call\","
1809+
"\"params\":{\"name\":\"search_code\","
1810+
"\"arguments\":{\"pattern\":\"HandleRequest\",\"project\":\"cjk-search\"}}}");
1811+
ASSERT_NOT_NULL(resp);
1812+
char *inner = extract_text_content(resp);
1813+
ASSERT_NOT_NULL(inner);
1814+
1815+
int grep_matches = -1;
1816+
const char *g = strstr(inner, "\"total_grep_matches\":");
1817+
if (g) {
1818+
sscanf(g, "\"total_grep_matches\":%d", &grep_matches);
1819+
}
1820+
ASSERT_TRUE(grep_matches > 0);
1821+
1822+
free(inner);
1823+
free(resp);
1824+
cbm_mcp_server_free(srv);
1825+
cbm_unlink(src_path);
1826+
cbm_rmdir(proj_dir);
1827+
cbm_rmdir(tmp);
1828+
PASS();
1829+
}
1830+
#endif
1831+
17581832
/* Shared fixture for the path_filter prefilter tests (PR #756 distilled):
17591833
* a project with two indexed files that both contain the search pattern —
17601834
* src/handler.go (inside the filter) and vendor/other.go (outside it). */
@@ -5210,6 +5284,9 @@ SUITE(mcp) {
52105284
RUN_TEST(tool_search_code_no_project);
52115285
RUN_TEST(search_code_multi_word);
52125286
RUN_TEST(search_code_scoped_path_with_spaces_issue687);
5287+
#ifdef _WIN32
5288+
RUN_TEST(search_code_scoped_path_with_cjk_root_issue903);
5289+
#endif
52135290
RUN_TEST(search_code_path_filter_prefilter_keeps_matches);
52145291
RUN_TEST(search_code_path_filter_matches_nothing);
52155292
RUN_TEST(search_code_invalid_regex_errors_issue283);

0 commit comments

Comments
 (0)