Skip to content

Commit 1a81ac0

Browse files
committed
feat: add native Linux64 support
Build and run EncodingFixTool as a native Linux64 executable. Make process, path, config, encoding, and Git handling platform-aware, and cover native Linux behavior including Unicode and rename/copy porcelain records.
1 parent 54ad42b commit 1a81ac0

12 files changed

Lines changed: 415 additions & 86 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ modules/
8383
.aider*
8484
.agents/
8585
/bin/*.cmds
86+
/bin/Linux64/
87+
/src/dcu/
8688
/dist/
8789
*.log
8890
/issues/

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Added
6+
7+
- Added a native Delphi Linux64 build at `bin/Linux64/EncodingFixTool`, including native regression coverage for encoding repair, CRLF normalization, backups, XDG configuration, Git-changed scope, shell quoting, and case-sensitive paths.
8+
9+
### Changed
10+
11+
- Changed `EncodingFixTool.sh` to launch the native Linux64 executable directly instead of invoking the Windows EXE through WSL interoperability.
12+
- Made Git execution, shell quoting, user config discovery, and path containment platform-correct; Linux avoids treating its UTF-8 default encoding as a legacy ANSI candidate while Windows retains active-code-page compatibility.
13+
314
## [v1.5] - 2026-06-24
415

516
### Fixed

README.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# EncodingFixTool
22

33
A fast, parallel, command-line fixer for Delphi source file encodings.
4-
It scans a directory tree or one explicit file; detects UTF-8/ASCII vs. legacy single-byte encodings; repairs mixed lines (Windows-1250/1252/ANSI), and writes clean UTF-8 with an optional BOM. Line endings are preserved by default, or normalized to Windows CRLF when requested.
4+
It scans a directory tree or one explicit file; detects UTF-8/ASCII vs. legacy single-byte encodings; repairs mixed lines (Windows-1250/1252, plus the active ANSI code page on Windows), and writes clean UTF-8 with an optional BOM. Line endings are preserved by default, or normalized to Windows CRLF when requested.
55

66
---
77

@@ -43,6 +43,17 @@ EncodingFixTool ext="*.pas,*.dpr, .dfm"
4343

4444
> Tip: Parameters accept `key=value` or `key:value`. You can prefix flags with `-` (and `/` on Windows), e.g. `-v`, `-dry`.
4545
46+
### Windows and Linux
47+
48+
The Windows build is `bin\EncodingFixTool.exe`. The native Linux64 build is `bin/Linux64/EncodingFixTool`.
49+
From Linux or WSL, use the thin launcher so arguments remain native Linux paths:
50+
51+
```bash
52+
./bin/EncodingFixTool.sh path=./src preset=delphi-ai format=json
53+
```
54+
55+
The launcher executes the Linux64 ELF binary directly. It does not start a Windows process and does not require WSL Windows interoperability or `wslpath`.
56+
4657
---
4758

4859
## Parameters
@@ -97,7 +108,7 @@ C:\bkp\src\foo\bar\Main.pas
97108
* For each line, try:
98109

99110
* **UTF-8 (strict)** — if it round-trips, use it.
100-
* **Windows-1250** (Central Europe/PL), **Windows-1252** (Western/DE), and **ANSI** — decode and **score**:
111+
* **Windows-1250** (Central Europe/PL) and **Windows-1252** (Western/DE) — decode and **score**. Windows builds also score the active system ANSI code page; Linux does not treat its UTF-8 default encoding as ANSI:
101112

102113
* +2 for valid Polish/German diacritics,
103114
* +1 for typical source characters (letters/digits/whitespace/common punctuation),
@@ -165,6 +176,12 @@ For AI coding agents working in Delphi projects, run the cleanup from the reposi
165176
EncodingFixTool path=. preset=delphi-ai scope=git-changed format=json
166177
```
167178

179+
From Linux or WSL:
180+
181+
```bash
182+
EncodingFixTool.sh path=. preset=delphi-ai scope=git-changed format=json
183+
```
184+
168185
This command is intentionally compact for agent workflows:
169186

170187
* `preset=delphi-ai` applies the Delphi cleanup defaults.
@@ -206,7 +223,7 @@ Example prompt:
206223
After editing Delphi files, use the EncodingFix Delphi cleanup skill before running the build.
207224
```
208225

209-
The skill itself is self-contained, but the `EncodingFixTool` executable must be available on `PATH` or via a repo-local path such as `.\bin\EncodingFixTool.exe`.
226+
The skill itself is self-contained, but the platform executable must be available on `PATH` or through the repo-local Windows EXE / Linux shell launcher.
210227

211228
### Use with Claude Code
212229

@@ -227,7 +244,8 @@ User-defined presets are JSON objects under a top-level `presets` key. Configura
227244
Recommended locations:
228245

229246
* Repo-local: `.encodingfix.json`, discovered from `path` upward.
230-
* User-global: `%APPDATA%\MaxLogic\EncodingFixTool\config.json`.
247+
* User-global on Windows: `%APPDATA%\MaxLogic\EncodingFixTool\config.json`.
248+
* User-global on Linux: `$XDG_CONFIG_HOME/MaxLogic/EncodingFixTool/config.json`, falling back to `$HOME/.config/MaxLogic/EncodingFixTool/config.json`.
231249
* Explicit one-off: pass `config=path\to\config.json`.
232250

233251
Precedence is conservative and predictable:

TASKS.md

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Tasks
22

3-
Next task ID: T-008
3+
Next task ID: T-010
44

55
## Summary
6-
Open tasks: 0 (In Progress: 0, Next Today: 0, Next This Week: 0, Next Later: 0, Blocked: 0)
7-
Done tasks: 7
6+
Open tasks: 1 (In Progress: 0, Next Today: 0, Next This Week: 0, Next Later: 1, Blocked: 0)
7+
Done tasks: 8
88

99
## In Progress
1010

@@ -14,10 +14,48 @@ Done tasks: 7
1414

1515
## Next - Later
1616

17+
### T-009 [CLI] Bound POSIX child-process execution
18+
Outcome:
19+
- Linux command execution enforces the same 30-second upper bound as Windows without depending on an optional external `timeout` command.
20+
- Timeout cleanup terminates and reaps the child process without leaving Git processes behind.
21+
- Native Linux regression coverage verifies successful commands and timeout behavior.
22+
Proof:
23+
- Run: `wsl.exe -e bash tests/Invoke-EncodingFixTool.Linux64.Tests.sh`
24+
Expect: exit=0, timeout regression passes, and no test-owned child process remains.
25+
- Run: `& $env:DAK_EXE build --project src\EncodingFixTool.dproj --delphi 23.0 --platform Linux64 --config Release --target Rebuild --ai --show-warnings`
26+
Expect: exit=0, zero warnings, zero errors.
27+
Touches: src/EncodingFixToolCore.pas, tests/Invoke-EncodingFixTool.Linux64.Tests.sh
28+
Verify: integration-test, build-only
29+
1730
## Blocked
1831

1932
## Done
2033

34+
### T-008 [CLI] Add native Linux64 support
35+
Completed: 2026-07-10
36+
Outcome:
37+
- `EncodingFixTool.dproj` builds a native Linux64 executable at `bin/Linux64/EncodingFixTool` while preserving Win32 and Win64 builds.
38+
- Platform-sensitive process execution, Git integration, shell quoting, user config lookup, paths, encodings, and line endings behave correctly on Windows and Linux.
39+
- `EncodingFixTool.sh` launches the native Linux64 binary directly without `wslpath` or Windows executable interop.
40+
- Native Linux regression coverage verifies ELF execution, CRLF cleanup, legacy encoding conversion, config lookup, backups, case-sensitive paths, and Git paths including Unicode, rename, and copy records.
41+
- README, agent-skill guidance, and CHANGELOG document the native Linux workflow.
42+
Proof:
43+
- PASS: `& $env:DAK_EXE build --project src\EncodingFixTool.dproj --delphi 23.0 --platform Linux64 --config Release --target Rebuild --ai --show-warnings`
44+
Result: exit=0, zero warnings, zero errors, ELF artifact exists, and the Windows resource hash is preserved.
45+
- PASS: `wsl.exe -e bash tests/Invoke-EncodingFixTool.Linux64.Tests.sh`
46+
Result: exit=0, output contains `EncodingFixTool Linux64 tests passed.`
47+
- PASS: `.\bin\EncodingFixTool.Tests.exe`
48+
Result: exit=0, 31 passed, 0 failed, 0 ignored.
49+
- PASS: `powershell -NoProfile -ExecutionPolicy Bypass -File tests\Invoke-EncodingFixTool.Tests.ps1`
50+
Result: exit=0, output contains `EncodingFixTool CLI tests passed.`
51+
- PASS: Win32 and Win64 Release rebuilds through DelphiAIKit with warnings enabled.
52+
Result: exit=0, zero warnings, zero errors for both platforms.
53+
- PASS: PowerShell Script Analyzer, ShellCheck, Bash syntax, project XML parsing, and `git diff --check`.
54+
Result: no findings.
55+
Touches: src/EncodingFixTool.dpr, src/EncodingFixTool.dproj, src/EncodingFixTool.res, src/EncodingFixToolCore.pas, bin/EncodingFixTool.sh, tests/Invoke-EncodingFixTool.Linux64.Tests.sh, README.md, agent-skill/encodingfix-delphi-cleanup/SKILL.md, agent-skill/encodingfix-delphi-cleanup/references/encodingfix-tool.md, CHANGELOG.md
56+
Verify: integration-test, cli-proof, build-only
57+
Notes: The approved design keeps `sLineBreak` for platform-native console help and explicit `#13#10` for `eol=crlf`. Linux user config follows XDG with `$HOME/.config` fallback. RED/GREEN was strict for native artifact, Linux path containment, and Unicode Git paths; supplementary platform and rename/copy coverage was completed under GREEN.
58+
2159
### T-007 [CLI] Support single-file path targets
2260
Completed: 2026-06-16
2361
Outcome:

agent-skill/encodingfix-delphi-cleanup/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ If unrelated user changes are dirty, avoid broad cleanup. Narrow `path=...`, ove
2828

2929
2. In a Git worktree, prefer the AI cleanup preset.
3030

31-
From WSL, run the Bash wrapper so WSL paths are converted before the Windows executable receives them. If the repo `bin` directory is on `PATH`, prefer:
31+
From Linux or WSL, run the Bash wrapper. It launches the native Linux64 binary directly, so Linux paths are passed through unchanged and WSL Windows interoperability is not involved. If the repo `bin` directory is on `PATH`, prefer:
3232

3333
```bash
3434
EncodingFixTool.sh path=. preset=delphi-ai scope=git-changed format=json

agent-skill/encodingfix-delphi-cleanup/references/encodingfix-tool.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Use this reference when the standard `preset=delphi-ai scope=git-changed` workfl
44

55
## Runtime Dependency
66

7-
Prefer `EncodingFixTool` from `PATH`. If unavailable, use a repo-local executable such as `.\bin\EncodingFixTool.exe`.
7+
Prefer `EncodingFixTool` from `PATH` on Windows or `EncodingFixTool.sh` on Linux/WSL. Repo-local paths are `.\bin\EncodingFixTool.exe` on Windows and `./bin/EncodingFixTool.sh` on Linux/WSL. The shell launcher executes `bin/Linux64/EncodingFixTool` directly and does not use Windows interoperability.
88

99
## Delphi AI Preset
1010

@@ -55,6 +55,8 @@ Repo presets may live in `.encodingfix.json`; user presets may live in:
5555

5656
```text
5757
%APPDATA%\MaxLogic\EncodingFixTool\config.json
58+
$XDG_CONFIG_HOME/MaxLogic/EncodingFixTool/config.json
59+
$HOME/.config/MaxLogic/EncodingFixTool/config.json
5860
```
5961

6062
Preset precedence:

bin/EncodingFixTool.sh

100644100755
Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,11 @@
22
set -euo pipefail
33

44
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
5-
exe_path="$script_dir/EncodingFixTool.exe"
5+
tool_path="$script_dir/Linux64/EncodingFixTool"
66

7-
if [[ ! -f "$exe_path" ]]; then
8-
printf 'EncodingFixTool.exe not found next to %s\n' "$0" >&2
7+
if [[ ! -x "$tool_path" ]]; then
8+
printf 'EncodingFixTool Linux64 executable not found or not executable: %s\n' "$tool_path" >&2
99
exit 127
1010
fi
1111

12-
is_windows_path() {
13-
[[ "$1" =~ ^[A-Za-z]:[\\/].* || "$1" =~ ^\\\\.* ]]
14-
}
15-
16-
to_windows_path() {
17-
local value="$1"
18-
19-
if [[ -z "$value" ]] || is_windows_path "$value"; then
20-
printf '%s' "$value"
21-
return
22-
fi
23-
24-
wslpath -aw -- "$value"
25-
}
26-
27-
convert_arg() {
28-
local arg="$1"
29-
30-
if [[ "$arg" =~ ^(-{0,2}|/)(path|config|bkp-dir)([:=])(.*)$ ]]; then
31-
printf '%s%s%s%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "$(to_windows_path "${BASH_REMATCH[4]}")"
32-
else
33-
printf '%s' "$arg"
34-
fi
35-
}
36-
37-
shopt -s nocasematch
38-
converted_args=()
39-
for arg in "$@"; do
40-
converted_args+=("$(convert_arg "$arg")")
41-
done
42-
43-
exec "$exe_path" "${converted_args[@]}"
12+
exec "$tool_path" "$@"

src/EncodingFixTool.dpr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
program EncodingFixTool;
22

33
{$APPTYPE CONSOLE}
4+
{$IFDEF MSWINDOWS}
45
{$R *.res}
6+
{$ENDIF}
57

68
uses
79
System.SysUtils,

src/EncodingFixTool.dproj

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<Base>True</Base>
66
<Config Condition="'$(Config)'==''">Release</Config>
77
<ProjectName Condition="'$(ProjectName)'==''">EncodingFixTool</ProjectName>
8-
<TargetedPlatforms>693377</TargetedPlatforms>
8+
<TargetedPlatforms>131</TargetedPlatforms>
99
<AppType>Console</AppType>
1010
<FrameworkType>None</FrameworkType>
1111
<ProjectVersion>20.2</ProjectVersion>
@@ -29,6 +29,11 @@
2929
<CfgParent>Base</CfgParent>
3030
<Base>true</Base>
3131
</PropertyGroup>
32+
<PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Base)'=='true') or '$(Base_Linux64)'!=''">
33+
<Base_Linux64>true</Base_Linux64>
34+
<CfgParent>Base</CfgParent>
35+
<Base>true</Base>
36+
</PropertyGroup>
3237
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
3338
<Base_Win32>true</Base_Win32>
3439
<CfgParent>Base</CfgParent>
@@ -87,7 +92,6 @@
8792
<DCC_N>false</DCC_N>
8893
<DCC_S>false</DCC_S>
8994
<DCC_ImageBase>00400000</DCC_ImageBase>
90-
<SanitizedProjectName>EncodingFixTool</SanitizedProjectName>
9195
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
9296
<VerInfo_MajorVer>1</VerInfo_MajorVer>
9397
<VerInfo_MinorVer>5</VerInfo_MinorVer>
@@ -150,6 +154,14 @@
150154
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.5.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.5.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
151155
<VerInfo_Locale>1033</VerInfo_Locale>
152156
</PropertyGroup>
157+
<PropertyGroup Condition="'$(Base_Linux64)'!=''">
158+
<BRCC_OutputDir>.\dcu\Linux64\$(Config)</BRCC_OutputDir>
159+
<DCC_ExeOutput>..\bin\Linux64</DCC_ExeOutput>
160+
<DCC_Namespace>Posix;System.Posix;$(DCC_Namespace)</DCC_Namespace>
161+
<Icon_MainIcon></Icon_MainIcon>
162+
<Icns_MainIcns></Icns_MainIcns>
163+
<VerInfo_IncludeVerInfo>false</VerInfo_IncludeVerInfo>
164+
</PropertyGroup>
153165
<PropertyGroup Condition="'$(Cfg_1)'!=''">
154166
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
155167
<DCC_DebugInformation>0</DCC_DebugInformation>
@@ -207,27 +219,20 @@
207219
<Source>
208220
<Source Name="MainSource">EncodingFixTool.dpr</Source>
209221
</Source>
210-
<Excluded_Packages>
211-
<Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\23.0\Bpl\wPDF5_DX14_Pack.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\23.0\Bpl\wPDF5_DX14_Pack.bpl not found</Excluded_Packages>
212-
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
213-
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
214-
<Excluded_Packages Name="F:\TMS-SmartSetUp\.tmssetup\build\bpl\Win32\VCL_TMSVCLGridExcelBridge_DESIGN290.bpl">TMS VCL Grid Excel Bridge (Design)</Excluded_Packages>
215-
</Excluded_Packages>
216222
</Delphi.Personality>
217223
<Platforms>
218224
<Platform value="Android">False</Platform>
219-
<Platform value="Android64">True</Platform>
220-
<Platform value="iOSDevice64">True</Platform>
221-
<Platform value="iOSSimARM64">True</Platform>
225+
<Platform value="Android64">False</Platform>
226+
<Platform value="iOSDevice64">False</Platform>
227+
<Platform value="iOSSimARM64">False</Platform>
222228
<Platform value="Linux64">True</Platform>
223-
<Platform value="OSX64">True</Platform>
224-
<Platform value="OSXARM64">True</Platform>
229+
<Platform value="OSX64">False</Platform>
230+
<Platform value="OSXARM64">False</Platform>
225231
<Platform value="Win32">True</Platform>
226232
<Platform value="Win64">True</Platform>
227233
</Platforms>
228234
</BorlandProject>
229235
<ProjectFileVersion>12</ProjectFileVersion>
230236
</ProjectExtensions>
231237
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
232-
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
233238
</Project>

src/EncodingFixTool.res

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)