From 7974b237bfd32a0d3bf698073582877d6af7476e Mon Sep 17 00:00:00 2001 From: kgfly <12282281+kgfly@users.noreply.github.com> Date: Sun, 23 Aug 2026 05:22:26 +0000 Subject: [PATCH 1/2] nerd-font --- .github/workflows/build-matrix.yml | 27 ++++++++++++++++++++++----- .github/workflows/nightly.yml | 13 +++++++++++-- .github/workflows/package.yml | 13 ++++++++++--- README.md | 3 ++- packaging/macos/make-dmg.sh | 14 +++++++++++++- packaging/windows/simplenvim.iss | 4 ++-- src/cmd/simplenvim/app.rc | 1 + src/internal/app/app.go | 17 +++++++++++++++++ src/internal/render/metrics.go | 6 ++++-- src/test/unit/render_test.go | 25 +++++++++++++++++++++++++ 10 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 src/cmd/simplenvim/app.rc diff --git a/.github/workflows/build-matrix.yml b/.github/workflows/build-matrix.yml index d6284a0..34a2bd7 100644 --- a/.github/workflows/build-matrix.yml +++ b/.github/workflows/build-matrix.yml @@ -57,6 +57,21 @@ jobs: # macOS needs nothing extra: Cocoa/Metal ship with the OS, and the # runners already have the Xcode command-line tools installed. + - name: Embed Windows icon resource + if: matrix.goos == 'windows' + shell: bash + run: | + set -euo pipefail + pip install Pillow --quiet + python3 -c " + from PIL import Image + img = Image.open('src/internal/app/icon.png') + img.save('src/cmd/simplenvim/icon.ico', format='ICO', + sizes=[(16,16),(32,32),(48,48),(64,64),(128,128),(256,256)]) + " + cd src/cmd/simplenvim + windres -o app_windows.syso app.rc + - name: Build working-directory: src shell: bash @@ -76,15 +91,17 @@ jobs: shell: bash run: | set -euo pipefail - name="simplenvim_${{ inputs.version }}_${{ matrix.goos }}_${{ matrix.goarch }}" + archive="simplenvim_${{ inputs.version }}_${{ matrix.goos }}_${{ matrix.goarch }}" + dir="simplenvim_${{ matrix.goos }}_${{ matrix.goarch }}" + mkdir -p "dist/${dir}" + cp dist/simplenvim$([ "${{ matrix.goos }}" = "windows" ] && echo .exe) LICENSE README.md "dist/${dir}/" cd dist - cp ../LICENSE ../README.md . if [ "${{ matrix.goos }}" = "windows" ]; then - 7z a "${name}.zip" simplenvim.exe LICENSE README.md + 7z a "${archive}.zip" "${dir}/" else - tar czf "${name}.tar.gz" simplenvim LICENSE README.md + tar czf "${archive}.tar.gz" "${dir}/" fi - rm -f simplenvim simplenvim.exe LICENSE README.md + rm -rf "${dir}" simplenvim simplenvim.exe LICENSE README.md 2>/dev/null || true ls -l - name: Upload artifact diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e88714a..99ae4ff 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -96,14 +96,23 @@ jobs: - uses: actions/download-artifact@v4 with: - path: dist + path: staging merge-multiple: true + - name: Collect release assets + run: | + set -euo pipefail + mkdir -p dist + find staging -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.deb' \ + -o -name '*.rpm' -o -name '*.exe' -o -name '*.dmg' -o -name '*.msi' \ + -o -name '*.pkg.tar.zst' \) -exec mv -t dist/ {} + + ls -l dist + - name: Generate checksums working-directory: dist run: | set -euo pipefail - find . -maxdepth 1 -type f ! -name SHA256SUMS.txt -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS.txt + sha256sum * > SHA256SUMS.txt cat SHA256SUMS.txt - name: Publish dated pre-release diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 2fcdcea..809c474 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -46,7 +46,7 @@ jobs: run: | set -euo pipefail mkdir -p stage - tar xzf incoming/*.tar.gz -C stage + tar xzf incoming/*.tar.gz --strip-components=1 -C stage chmod +x stage/simplenvim ls -l stage @@ -59,7 +59,12 @@ jobs: mkdir -p dist nfpm package -f packaging/nfpm.yaml -p deb -t dist/ nfpm package -f packaging/nfpm.yaml -p rpm -t dist/ - ls -l dist + # Rename to include "linux" in filenames for clarity. + cd dist + for f in *.deb *.rpm; do + mv "$f" "$(echo "$f" | sed 's/^simplenvim_/simplenvim_linux_/' | sed 's/^simplenvim-/simplenvim-linux-/')" + done + ls -l - uses: actions/upload-artifact@v4 with: @@ -87,6 +92,8 @@ jobs: set -euo pipefail mkdir -p stage unzip -o incoming/*.zip -d stage + # Flatten the subdirectory created by the archive step. + mv stage/simplenvim_*/* stage/ 2>/dev/null || true ls -l stage - name: Compile installer @@ -170,7 +177,7 @@ jobs: set -euo pipefail mkdir -p stage dist - tar xzf incoming/*.tar.gz -C stage + tar xzf incoming/*.tar.gz --strip-components=1 -C stage chmod +x stage/simplenvim if [ "$ARCH" = "amd64" ]; then pkgarch="x86_64"; else pkgarch="aarch64"; fi diff --git a/README.md b/README.md index df34c5c..fb3aae1 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,13 @@ binary. Nvim's own input protocol. - Live window resizing. - A small, plain `config.toml` for font and Nvim-launch settings. +- Nerd font support. Simple and pure — no bloat, no bundled plugin marketplace, no telemetry. ## Installing -**Note: all installation packages are exclusively generated by github free CD pipeline. No 3rd party is involved, during the package creation.** +**Note: all installation packages are exclusively generated by github CI-CD pipeline. No 3rd party is involved, during the package creation.** Grab a build for your platform from the [Releases page](https://github.com/kgfly/SimpleNvimEditor/releases). diff --git a/packaging/macos/make-dmg.sh b/packaging/macos/make-dmg.sh index d0f4c77..1ca99cb 100755 --- a/packaging/macos/make-dmg.sh +++ b/packaging/macos/make-dmg.sh @@ -21,7 +21,7 @@ rm -rf build dist mkdir -p build dist echo "==> Extracting binary" -tar xzf incoming/*.tar.gz -C build +tar xzf incoming/*.tar.gz --strip-components=1 -C build chmod +x build/simplenvim echo "==> Assembling ${BUNDLE}" @@ -29,6 +29,17 @@ mkdir -p "build/${BUNDLE}/Contents/MacOS" mkdir -p "build/${BUNDLE}/Contents/Resources" mv build/simplenvim "build/${BUNDLE}/Contents/MacOS/simplenvim" +# Build an .icns icon set from the embedded icon.png. +ICONSET="build/AppIcon.iconset" +mkdir -p "${ICONSET}" +ICON_SRC="src/internal/app/icon.png" +for sz in 16 32 64 128 256 512; do + sips -z ${sz} ${sz} "${ICON_SRC}" --out "${ICONSET}/icon_${sz}x${sz}.png" >/dev/null + dbl=$((sz * 2)) + sips -z ${dbl} ${dbl} "${ICON_SRC}" --out "${ICONSET}/icon_${sz}x${sz}@2x.png" >/dev/null +done +iconutil -c icns "${ICONSET}" -o "build/${BUNDLE}/Contents/Resources/AppIcon.icns" + cat > "build/${BUNDLE}/Contents/Info.plist" < @@ -42,6 +53,7 @@ cat > "build/${BUNDLE}/Contents/Info.plist" <CFBundleExecutable simplenvim CFBundlePackageType APPL CFBundleSignature ???? + CFBundleIconFile AppIcon LSMinimumSystemVersion 11.0 NSHighResolutionCapable NSSupportsAutomaticGraphicsSwitching diff --git a/packaging/windows/simplenvim.iss b/packaging/windows/simplenvim.iss index fa0bc3f..c5d4f3e 100644 --- a/packaging/windows/simplenvim.iss +++ b/packaging/windows/simplenvim.iss @@ -55,8 +55,8 @@ Source: "..\..\LICENSE"; DestDir: "{app}"; Flags: ignoreversion Source: "..\..\README.md"; DestDir: "{app}"; Flags: ignoreversion [Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\{#MyAppExeName}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Registry] Root: HKA; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; \ diff --git a/src/cmd/simplenvim/app.rc b/src/cmd/simplenvim/app.rc new file mode 100644 index 0000000..a841e99 --- /dev/null +++ b/src/cmd/simplenvim/app.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON "icon.ico" diff --git a/src/internal/app/app.go b/src/internal/app/app.go index 5a05358..96a785c 100644 --- a/src/internal/app/app.go +++ b/src/internal/app/app.go @@ -149,6 +149,11 @@ func (a *App) handleInput(gtx layout.Context) { event.Op(gtx.Ops, rootTag) area.Pop() + // Tell Gio this tag is an active text-input client so the platform + // layer (NSTextInputClient on macOS) routes IME and voice dictation + // through EditEvent instead of swallowing it. + key.InputHintOp{Tag: rootTag, Hint: key.HintAny}.Add(gtx.Ops) + if !a.focused { gtx.Execute(key.FocusCmd{Tag: rootTag}) } @@ -164,6 +169,8 @@ func (a *App) handleInput(gtx layout.Context) { a.focused = ev.Focus case key.Event: a.onKey(ev) + case key.EditEvent: + a.onEdit(ev) case pointer.Event: a.onPointer(ev) } @@ -179,6 +186,16 @@ func (a *App) onKey(e key.Event) { } } +// onEdit forwards text produced by an input method (macOS Dictation, CJK +// IME, Emoji picker, etc.) to Nvim. EditEvent.Text may contain multiple +// characters; Nvim's nvim_input accepts them as a UTF-8 byte string. +func (a *App) onEdit(e key.EditEvent) { + if a.proc == nil || e.Text == "" { + return + } + a.proc.Input(e.Text) +} + func (a *App) onPointer(e pointer.Event) { if a.proc == nil || a.fonts.Metrics.CellWidth == 0 { return diff --git a/src/internal/render/metrics.go b/src/internal/render/metrics.go index 747b5da..4e93839 100644 --- a/src/internal/render/metrics.go +++ b/src/internal/render/metrics.go @@ -39,10 +39,12 @@ type Fonts struct { // NewShaper builds a text shaper according to the configuration: either the // bundled, fully self-contained Go Mono typeface (the default, chosen so // the app renders identically regardless of what's installed on the host), -// or the system font matcher when the user opts in. +// or the system font matcher when the user opts in. System-font mode still +// includes the bundled Go Mono as a fallback so text never disappears if a +// configured family can't be found. func NewShaper(cfg config.EditorConfig) *text.Shaper { if cfg.UseSystemFonts { - return text.NewShaper() + return text.NewShaper(text.WithCollection(gofont.Collection())) } return text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) } diff --git a/src/test/unit/render_test.go b/src/test/unit/render_test.go index 1b74cd3..ad4fc2c 100644 --- a/src/test/unit/render_test.go +++ b/src/test/unit/render_test.go @@ -220,3 +220,28 @@ func TestFrameWithEmptyTextCells(t *testing.T) { }) runFrame(t, s.Snapshot()) } + +func TestFrameCursorZeroPercentage(t *testing.T) { + s := uistate.New() + s.Apply([][]interface{}{ + {"grid_resize", []interface{}{1, 10, 5}}, + {"grid_cursor_goto", []interface{}{1, 0, 0}}, + {"mode_info_set", []interface{}{true, []interface{}{ + map[string]interface{}{"cursor_shape": "vertical", "cell_percentage": 0}, + }}}, + {"mode_change", []interface{}{"normal", 0}}, + }) + runFrame(t, s.Snapshot()) +} + +func TestFrameWithPlacedSplitWindow(t *testing.T) { + s := uistate.New() + s.Apply([][]interface{}{ + {"grid_resize", []interface{}{1, 40, 20}}, + {"grid_resize", []interface{}{2, 20, 10}}, + {"win_pos", []interface{}{2, 0, 0, 0, 20, 10}}, + {"grid_line", []interface{}{2, 0, 0, []interface{}{[]interface{}{"hello split"}}}}, + {"grid_cursor_goto", []interface{}{2, 0, 5}}, + }) + runFrame(t, s.Snapshot()) +} From 011d96b27772b4fbe88a81fda26030ed4251b92c Mon Sep 17 00:00:00 2001 From: kgfly <12282281+kgfly@users.noreply.github.com> Date: Sun, 23 Aug 2026 05:25:35 +0000 Subject: [PATCH 2/2] COMMIT-2026_08_23-05_25_35 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb3aae1..f2a0e49 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Simple and pure — no bloat, no bundled plugin marketplace, no telemetry. ## Installing -**Note: all installation packages are exclusively generated by github CI-CD pipeline. No 3rd party is involved, during the package creation.** +**(All installation packages are exclusively generated by github CI-CD pipeline, where all github security check is on. No 3rd party is involved, during the package creation.)** Grab a build for your platform from the [Releases page](https://github.com/kgfly/SimpleNvimEditor/releases).