Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e9cee6c6 | ||
|
|
e701b416da | ||
|
|
a629a7fb0e | ||
|
|
c03b183228 |
@@ -21,7 +21,6 @@ Docker (cross-platform Linux testing): `docker build -t kte-linux . && docker ru
|
|||||||
- for GUI bugs: launch `./build/kge` and report what was seen; a green test suite is not proof
|
- for GUI bugs: launch `./build/kge` and report what was seen; a green test suite is not proof
|
||||||
|
|
||||||
## Rules (do not re-litigate)
|
## Rules (do not re-litigate)
|
||||||
- Release: bump CMakeLists version, checkpoint, `./make-release.sh`, report the SHA256 it prints; a GitHub push failure at the same commit is fine; then update `/opt/homebrew/Library/Taps/kisom/homebrew-tap`.
|
|
||||||
- All text mutations must go through the PieceTable API (`insert_text`, `delete_text`) so undo and swap recording work.
|
- All text mutations must go through the PieceTable API (`insert_text`, `delete_text`) so undo and swap recording work.
|
||||||
- Read lines with `Nrows()` and `GetLineString()` (a copy, cheap on any buffer) or `GetLineView()` (zero-copy when the line lies within one piece; a line straddling an edit materializes the whole buffer); `GetLineView()` and `ContentView()` are valid only until the next buffer modification.
|
- Read lines with `Nrows()` and `GetLineString()` (a copy, cheap on any buffer) or `GetLineView()` (zero-copy when the line lies within one piece; a line straddling an edit materializes the whole buffer); `GetLineView()` and `ContentView()` are valid only until the next buffer modification.
|
||||||
- C++20, compiled with `-Wall -Wextra -Werror -pedantic`; Clang uses `-stdlib=libc++`.
|
- C++20, compiled with `-Wall -Wextra -Werror -pedantic`; Clang uses `-stdlib=libc++`.
|
||||||
@@ -29,6 +28,28 @@ Docker (cross-platform Linux testing): `docker build -t kte-linux . && docker ru
|
|||||||
- Fallible ops use `bool func(args..., std::string &err)`: clear `err` at start, capture `errno` immediately after syscall failure, use EINTR-safe wrappers from `SyscallWrappers.h` instead of raw syscalls.
|
- Fallible ops use `bool func(args..., std::string &err)`: clear `err` at start, capture `errno` immediately after syscall failure, use EINTR-safe wrappers from `SyscallWrappers.h` instead of raw syscalls.
|
||||||
- After editing ops, call `ensure_cursor_visible()` to update the viewport.
|
- After editing ops, call `ensure_cursor_visible()` to update the viewport.
|
||||||
|
|
||||||
|
## Release
|
||||||
|
|
||||||
|
`KTE_VERSION` in `CMakeLists.txt` is the version to ship. Bump it and checkpoint only when asked to bump. `./make-release` refuses a dirty tree of tracked files.
|
||||||
|
|
||||||
|
`./make-release` (no `.sh`) tags `v${KTE_VERSION}`, pushes `master` and tags to `origin` (`git.wntrmute.dev:kyle/kte`) and `github` (`github.com:kisom/kte`), then runs `./make-app-release`. A GitHub rejection because that tag already points at this commit is fine; if the script stops before the app build, run `./make-app-release`. Stop if an existing tag points at a different commit.
|
||||||
|
|
||||||
|
`.github/workflows/release.yml` does not publish the release. Cancel the Actions run the tag push starts so it cannot replace a release created by hand. Publish with `gh`, tag already created, asset only `kge.app.zip`:
|
||||||
|
|
||||||
|
```
|
||||||
|
gh release create vX.Y.Z cmake-build-release/kge.app.zip \
|
||||||
|
--repo kisom/kte --title "vX.Y.Z" --notes-file /tmp/notes.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes are a short summary of commits since the previous tag. `./make-app-release` prints the zip SHA256. Re-download `https://github.com/kisom/kte/releases/download/vX.Y.Z/kge.app.zip` and confirm that hash. `kte` and the bundled `kge` must print `kte vX.Y.Z`.
|
||||||
|
|
||||||
|
Then update `/opt/homebrew/Library/Taps/kisom/homebrew-tap` and push. Leave unrelated dirty files in that checkout unstaged.
|
||||||
|
|
||||||
|
- `Formula/kte.rb`: URL `https://github.com/kisom/kte/archive/refs/tags/vX.Y.Z.tar.gz` and the SHA256 of that download. Commit message: `kte X.Y.Z`
|
||||||
|
- `Casks/kge.rb`: `version` and the published zip SHA256. The cask URL already uses `v#{version}`. Commit message: `kge -> X.Y.Z`
|
||||||
|
|
||||||
|
Report the zip SHA256, the release URL, and the tap commits.
|
||||||
|
|
||||||
## Docs that govern
|
## Docs that govern
|
||||||
- `docs/ke.md` — canonical keybinding/spec reference, inherited from the predecessor editor `ke`
|
- `docs/ke.md` — canonical keybinding/spec reference, inherited from the predecessor editor `ke`
|
||||||
- `REWRITE.md`, `ROADMAP.md`, `CONFIG.md` — design rationale, roadmap, and config reference
|
- `REWRITE.md`, `ROADMAP.md`, `CONFIG.md` — design rationale, roadmap, and config reference
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ project(kte)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(KTE_VERSION "1.13.0")
|
set(KTE_VERSION "1.14.0")
|
||||||
|
|
||||||
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
||||||
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
||||||
|
|||||||
+9
-1
@@ -1849,7 +1849,15 @@ cmd_font_set_by_name(const CommandContext &ctx)
|
|||||||
|
|
||||||
auto ® = FontRegistry::Instance();
|
auto ® = FontRegistry::Instance();
|
||||||
if (!reg.HasFont(name)) {
|
if (!reg.HasFont(name)) {
|
||||||
ctx.editor.SetStatus("font: unknown name");
|
// Build list of available fonts
|
||||||
|
const auto names = reg.FontNames();
|
||||||
|
std::string avail;
|
||||||
|
for (size_t i = 0; i < names.size(); ++i) {
|
||||||
|
if (i)
|
||||||
|
avail += ", ";
|
||||||
|
avail += names[i];
|
||||||
|
}
|
||||||
|
ctx.editor.SetStatus(std::string("Unknown font; available: ") + avail);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ enum class CommandId {
|
|||||||
// Editing
|
// Editing
|
||||||
InsertText, // arg: text to insert at cursor (UTF-8, no newlines)
|
InsertText, // arg: text to insert at cursor (UTF-8, no newlines)
|
||||||
Newline, // insert a newline at cursor
|
Newline, // insert a newline at cursor
|
||||||
SmartNewline, // insert a newline with auto-indent (Shift-Enter)
|
SmartNewline, // insert a newline with auto-indent (Enter)
|
||||||
Backspace, // delete char before cursor (may join lines)
|
Backspace, // delete char before cursor (may join lines)
|
||||||
DeleteChar, // delete char at cursor (may join lines)
|
DeleteChar, // delete char at cursor (may join lines)
|
||||||
KillToEOL, // delete from cursor to end of line; if at EOL, delete newline
|
KillToEOL, // delete from cursor to end of line; if at EOL, delete newline
|
||||||
|
|||||||
+413
@@ -770,6 +770,395 @@ SyntaxInkEverforest(const TokenKind k)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Amber: monochrome CRT amber/black with warm parchment text; cool teal/cyan
|
||||||
|
// accents provide contrast against the otherwise all-amber palette.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkAmber(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 text = RGBA(0xE6D5A3);
|
||||||
|
const ImVec4 amber = RGBA(0xFFB000);
|
||||||
|
const ImVec4 orange = RGBA(0xFF8C32);
|
||||||
|
const ImVec4 yellow = RGBA(0xFFD166);
|
||||||
|
const ImVec4 teal = RGBA(0x3AAFA9);
|
||||||
|
const ImVec4 cyan = RGBA(0x4CC9F0);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return amber;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return teal;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return ImVec4(text.x, text.y, text.z, 0.50f);
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return orange;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xFF5555);
|
||||||
|
default:
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// E-Ink: near-monochrome, restrained spot color (like Tufte) rather than a
|
||||||
|
// full rainbow, to match the grayscale reading-device aesthetic.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkEInk(const TokenKind k, const bool dark)
|
||||||
|
{
|
||||||
|
const ImVec4 ink = dark ? RGBA(0xEDEDEA) : RGBA(0x111111);
|
||||||
|
const ImVec4 dim = dark ? RGBA(0xB5B5B3) : RGBA(0x666666);
|
||||||
|
const ImVec4 navy = dark ? RGBA(0x86A6D6) : RGBA(0x2A4B7C);
|
||||||
|
const ImVec4 brick = dark ? RGBA(0xD98080) : RGBA(0x8B3A3A);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return navy;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return brick;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return dim;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return navy;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return dark ? RGBA(0xC8B27A) : RGBA(0x6B4C00);
|
||||||
|
case TokenKind::Error:
|
||||||
|
return brick;
|
||||||
|
default:
|
||||||
|
return ink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Gruvbox: authentic "retro groove" highlight-group mapping (red statements,
|
||||||
|
// yellow types, green strings, gray comments, purple constants).
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkGruvbox(const TokenKind k, const bool dark)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = dark ? RGBA(0xEBDBB2) : RGBA(0x3C3836);
|
||||||
|
const ImVec4 gray = dark ? RGBA(0x928374) : RGBA(0x7C6F64);
|
||||||
|
const ImVec4 red = dark ? RGBA(0xFB4934) : RGBA(0x9D0006);
|
||||||
|
const ImVec4 green = dark ? RGBA(0xB8BB26) : RGBA(0x79740E);
|
||||||
|
const ImVec4 yellow = dark ? RGBA(0xFABD2F) : RGBA(0xB57614);
|
||||||
|
const ImVec4 aqua = dark ? RGBA(0x8EC07C) : RGBA(0x427B58);
|
||||||
|
const ImVec4 purple = dark ? RGBA(0xD3869B) : RGBA(0x8F3F71);
|
||||||
|
const ImVec4 blue = dark ? RGBA(0x83A598) : RGBA(0x076678);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return red;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return gray;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return purple;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return aqua;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return red;
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Kanagawa Paper: sumi-ink text with wave/autumn accents drawn from the
|
||||||
|
// Kanagawa vim colorscheme, muted for the paper-light variant.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkKanagawaPaper(const TokenKind k, const bool dark)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = dark ? RGBA(0xDCD7BA) : RGBA(0x3A3A3A);
|
||||||
|
const ImVec4 gray = dark ? RGBA(0x9C9A8F) : RGBA(0x8A8674);
|
||||||
|
const ImVec4 violet = dark ? RGBA(0x957FB8) : RGBA(0x7D5C8A);
|
||||||
|
const ImVec4 green = dark ? RGBA(0x98BB6C) : RGBA(0x6F894E);
|
||||||
|
const ImVec4 orange = dark ? RGBA(0xFFA066) : RGBA(0xC4746E);
|
||||||
|
const ImVec4 blue = dark ? RGBA(0x7E9CD8) : RGBA(0x487AA1);
|
||||||
|
const ImVec4 red = dark ? RGBA(0xE46876) : RGBA(0xC34043);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return violet;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return gray;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return orange;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return red;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return red;
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LCARS: vibrant Star Trek console pastels against near-black.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkLCARS(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = RGBA(0xECECEC);
|
||||||
|
const ImVec4 dim = RGBA(0xBFBFC4);
|
||||||
|
const ImVec4 orange = RGBA(0xFF9966);
|
||||||
|
const ImVec4 yellow = RGBA(0xFFCC66);
|
||||||
|
const ImVec4 purple = RGBA(0xCC99FF);
|
||||||
|
const ImVec4 blue = RGBA(0x66CCFF);
|
||||||
|
const ImVec4 green = RGBA(0x99FFCC);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return orange;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return purple;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return dim;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return RGBA(0xFF99CC); // lcars pink
|
||||||
|
case TokenKind::Function:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xFF6666);
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Old Book: sepia/dark mapping lifted from the oldbook8.vim highlight groups
|
||||||
|
// already used for the ImGui chrome, so code reads as part of the same book.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkOldBook(const TokenKind k, const bool dark)
|
||||||
|
{
|
||||||
|
const ImVec4 ink = dark ? RGBA(0xD5D4D2) : RGBA(0x3B2F2F);
|
||||||
|
const ImVec4 dim = dark ? RGBA(0x626C77) : RGBA(0x5A4540);
|
||||||
|
const ImVec4 red = dark ? RGBA(0xDB6C6C) : RGBA(0xA65858);
|
||||||
|
const ImVec4 teal = dark ? RGBA(0x5BB899) : RGBA(0x3F7F7A);
|
||||||
|
const ImVec4 blue = dark ? RGBA(0x87D7FF) : RGBA(0x4F6D8C);
|
||||||
|
const ImVec4 yellow = dark ? RGBA(0xDDD668) : RGBA(0xB58B00);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return red;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return teal;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return dim;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return red;
|
||||||
|
default:
|
||||||
|
return ink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Orbital: deep-space dark with cool blues/cyans/magenta; a spot of green
|
||||||
|
// distinguishes strings from the otherwise blue-heavy palette.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkOrbital(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = RGBA(0xC8D3E5);
|
||||||
|
const ImVec4 dim = RGBA(0x9FB2CC);
|
||||||
|
const ImVec4 blue = RGBA(0x6AA2FF);
|
||||||
|
const ImVec4 cyan = RGBA(0x5AD1E6);
|
||||||
|
const ImVec4 magenta = RGBA(0xD681F8);
|
||||||
|
const ImVec4 yellow = RGBA(0xE6C17D);
|
||||||
|
const ImVec4 green = RGBA(0x7EE081);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return dim;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return magenta;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xFF6B6B);
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Plan 9 / acme: deliberately restrained — black ink on paper with acme's
|
||||||
|
// signature blue for structure, olive for strings, brick for errors.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkPlan9(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 ink = RGBA(0x000000);
|
||||||
|
const ImVec4 blueH = RGBA(0x4C8DFF);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return RGBA(0x0064FF); // acme blue
|
||||||
|
case TokenKind::Type:
|
||||||
|
case TokenKind::Function:
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return blueH;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return RGBA(0x7A6A00); // olive
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return ImVec4(0.0f, 0.0f, 0.0f, 0.55f);
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xB33A3A);
|
||||||
|
default:
|
||||||
|
return ink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Solarized: Ethan Schoonover's canonical accent-to-role mapping. Accent
|
||||||
|
// hues are shared between light/dark by design; only body/comment shift.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkSolarized(const TokenKind k, const bool dark)
|
||||||
|
{
|
||||||
|
const ImVec4 body = dark ? RGBA(0x839496) : RGBA(0x657b83);
|
||||||
|
const ImVec4 comment = RGBA(0x586e75); // base01
|
||||||
|
const ImVec4 yellow = RGBA(0xb58900);
|
||||||
|
const ImVec4 orange = RGBA(0xcb4b16);
|
||||||
|
const ImVec4 red = RGBA(0xdc322f);
|
||||||
|
const ImVec4 blue = RGBA(0x268bd2);
|
||||||
|
const ImVec4 cyan = RGBA(0x2aa198);
|
||||||
|
const ImVec4 green = RGBA(0x859900);
|
||||||
|
const ImVec4 violet = RGBA(0x6c71c4);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return yellow;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return comment;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return violet;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return orange;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return red;
|
||||||
|
default:
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Weyland-Yutani: corporate terminal black with hazard yellow/orange and a
|
||||||
|
// system-green for strings so the palette isn't purely amber-on-black.
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkWeylandYutani(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = RGBA(0xE6E6E6);
|
||||||
|
const ImVec4 dim = RGBA(0xBDBDBD);
|
||||||
|
const ImVec4 hazard = RGBA(0xFFC300);
|
||||||
|
const ImVec4 orange = RGBA(0xFF8C00);
|
||||||
|
const ImVec4 cyan = RGBA(0x4CC9F0);
|
||||||
|
const ImVec4 green = RGBA(0x6FCF97);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return hazard;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return green;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return dim;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return orange;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return cyan;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xFF4444);
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Zenburn: low-contrast dark palette, faces lifted from zenburn.vim
|
||||||
|
// (dim green comments, dusty-rose strings/constants, pale yellow keywords).
|
||||||
|
static ImVec4
|
||||||
|
SyntaxInkZenburn(const TokenKind k)
|
||||||
|
{
|
||||||
|
const ImVec4 fg = RGBA(0xDCDCCC);
|
||||||
|
const ImVec4 comment = RGBA(0x7F9F7F);
|
||||||
|
const ImVec4 str = RGBA(0xCC9393);
|
||||||
|
const ImVec4 keyword = RGBA(0xF0DFAF);
|
||||||
|
const ImVec4 type = RGBA(0xDFDFBF);
|
||||||
|
const ImVec4 func = RGBA(0xEFEF8F);
|
||||||
|
const ImVec4 blue = RGBA(0x8CD0D3);
|
||||||
|
switch (k) {
|
||||||
|
case TokenKind::Keyword:
|
||||||
|
return keyword;
|
||||||
|
case TokenKind::Type:
|
||||||
|
return type;
|
||||||
|
case TokenKind::String:
|
||||||
|
case TokenKind::Char:
|
||||||
|
return str;
|
||||||
|
case TokenKind::Comment:
|
||||||
|
return comment;
|
||||||
|
case TokenKind::Number:
|
||||||
|
case TokenKind::Constant:
|
||||||
|
return str;
|
||||||
|
case TokenKind::Preproc:
|
||||||
|
return blue;
|
||||||
|
case TokenKind::Function:
|
||||||
|
return func;
|
||||||
|
case TokenKind::Error:
|
||||||
|
return RGBA(0xE37170);
|
||||||
|
default:
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[[maybe_unused]] static ImVec4
|
[[maybe_unused]] static ImVec4
|
||||||
SyntaxInk(const TokenKind k)
|
SyntaxInk(const TokenKind k)
|
||||||
{
|
{
|
||||||
@@ -782,6 +1171,30 @@ SyntaxInk(const TokenKind k)
|
|||||||
return SyntaxInkLeuchtturm(k, dark);
|
return SyntaxInkLeuchtturm(k, dark);
|
||||||
if (gCurrentTheme == ThemeId::Everforest)
|
if (gCurrentTheme == ThemeId::Everforest)
|
||||||
return SyntaxInkEverforest(k);
|
return SyntaxInkEverforest(k);
|
||||||
|
if (gCurrentTheme == ThemeId::Amber)
|
||||||
|
return SyntaxInkAmber(k);
|
||||||
|
if (gCurrentTheme == ThemeId::EInk)
|
||||||
|
return SyntaxInkEInk(k, dark);
|
||||||
|
if (gCurrentTheme == ThemeId::GruvboxDarkMedium)
|
||||||
|
return SyntaxInkGruvbox(k, dark);
|
||||||
|
if (gCurrentTheme == ThemeId::KanagawaPaper)
|
||||||
|
return SyntaxInkKanagawaPaper(k, dark);
|
||||||
|
if (gCurrentTheme == ThemeId::LCARS)
|
||||||
|
return SyntaxInkLCARS(k);
|
||||||
|
if (gCurrentTheme == ThemeId::OldBook)
|
||||||
|
return SyntaxInkOldBook(k, dark);
|
||||||
|
if (gCurrentTheme == ThemeId::Orbital)
|
||||||
|
return SyntaxInkOrbital(k);
|
||||||
|
if (gCurrentTheme == ThemeId::Plan9)
|
||||||
|
return SyntaxInkPlan9(k);
|
||||||
|
if (gCurrentTheme == ThemeId::Solarized)
|
||||||
|
return SyntaxInkSolarized(k, dark);
|
||||||
|
if (gCurrentTheme == ThemeId::WeylandYutani)
|
||||||
|
return SyntaxInkWeylandYutani(k);
|
||||||
|
if (gCurrentTheme == ThemeId::Zenburn)
|
||||||
|
return SyntaxInkZenburn(k);
|
||||||
|
if (gCurrentTheme == ThemeId::Everforest)
|
||||||
|
return SyntaxInkEverforest(k);
|
||||||
|
|
||||||
// Default palettes tuned for Nord-ish themes
|
// Default palettes tuned for Nord-ish themes
|
||||||
const ImVec4 def = dark ? RGBA(0xD8DEE9) : RGBA(0x2E3440);
|
const ImVec4 def = dark ? RGBA(0xD8DEE9) : RGBA(0x2E3440);
|
||||||
|
|||||||
+7
-1
@@ -94,7 +94,13 @@ HelpText::Text()
|
|||||||
" orbital, plan9, solarized, tufte, weyland-yutani,\n"
|
" orbital, plan9, solarized, tufte, weyland-yutani,\n"
|
||||||
" zenburn)\n"
|
" zenburn)\n"
|
||||||
" : background MODE Background: light | dark\n"
|
" : background MODE Background: light | dark\n"
|
||||||
" : font NAME Set font (tab completes)\n"
|
" : font NAME Set font (tab completes; b612, berkeley,\n"
|
||||||
|
" berkeley-bold, brassmono, brassmono-bold,\n"
|
||||||
|
" brassmonocode, brassmonocode-bold, crimsonpro,\n"
|
||||||
|
" default, etbook, fira, go, ibm, idealist,\n"
|
||||||
|
" inconsolata, inconsolataex, iosevka, iosevkaex,\n"
|
||||||
|
" sharetech, space, spectral, syne, triplicate,\n"
|
||||||
|
" unispace)\n"
|
||||||
" : font-size NUM Set font size in pixels\n"
|
" : font-size NUM Set font size in pixels\n"
|
||||||
" : mode [code|writing] Toggle or set edit mode\n"
|
" : mode [code|writing] Toggle or set edit mode\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|||||||
@@ -139,11 +139,7 @@ map_key(const SDL_Keycode key,
|
|||||||
case SDLK_KP_ENTER:
|
case SDLK_KP_ENTER:
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
k_ctrl_pending = false;
|
k_ctrl_pending = false;
|
||||||
if (mod & KMOD_SHIFT) {
|
out = {true, KEnterCommand((mod & KMOD_SHIFT) != 0), "", 0};
|
||||||
out = {true, CommandId::SmartNewline, "", 0};
|
|
||||||
} else {
|
|
||||||
out = {true, CommandId::Newline, "", 0};
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
case SDLK_ESCAPE:
|
case SDLK_ESCAPE:
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
|
|||||||
+9
-2
@@ -235,10 +235,17 @@ KLookupEscCommand(const int ascii_key, CommandId &out) -> bool
|
|||||||
return true;
|
return true;
|
||||||
case '\n':
|
case '\n':
|
||||||
case '\r':
|
case '\r':
|
||||||
out = CommandId::SmartNewline; // Shift+Enter (some terminals send this as Alt+Enter sequences)
|
out = KEnterCommand(true); // ESC-Enter: raw newline (terminals rarely send Shift+Enter)
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto
|
||||||
|
KEnterCommand(const bool raw) -> CommandId
|
||||||
|
{
|
||||||
|
return raw ? CommandId::Newline : CommandId::SmartNewline;
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ bool KLookupCtrlCommand(int ascii_key, CommandId &out);
|
|||||||
// ascii_key should be the lowercase ASCII of the letter.
|
// ascii_key should be the lowercase ASCII of the letter.
|
||||||
bool KLookupEscCommand(int ascii_key, CommandId &out);
|
bool KLookupEscCommand(int ascii_key, CommandId &out);
|
||||||
|
|
||||||
|
// Enter: copy indent from the current line. Shift+Enter (GUI) and ESC-Enter
|
||||||
|
// (terminal) insert a raw newline at column 0.
|
||||||
|
CommandId KEnterCommand(bool raw);
|
||||||
|
|
||||||
// Utility: normalize an int keycode to lowercased ASCII if it's in printable range.
|
// Utility: normalize an int keycode to lowercased ASCII if it's in printable range.
|
||||||
inline int
|
inline int
|
||||||
KLowerAscii(const int key)
|
KLowerAscii(const int key)
|
||||||
|
|||||||
@@ -130,6 +130,17 @@ cmake --build cmake-build-debug
|
|||||||
./cmake-build-debug/kte --gui [files]
|
./cmake-build-debug/kte --gui [files]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Theming and Fonts
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The GUI (`kge`) ships with 15 built-in color themes (several with
|
||||||
|
light/dark variants), each with a matching syntax-highlighting
|
||||||
|
palette, plus two dozen embedded fonts. Switch either at runtime from
|
||||||
|
the command prompt with `: theme NAME` and `: font NAME` (both tab-
|
||||||
|
complete), or set defaults in `~/.config/kte/kge.toml`. `: help` lists
|
||||||
|
the available theme and font names; see `docs/themes.md` for the full
|
||||||
|
theme reference and how to add a new one.
|
||||||
|
|
||||||
Status
|
Status
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ map_key_to_command(const int ch,
|
|||||||
// ESC marks the next key as Meta. Consume that flag on every other key up
|
// ESC marks the next key as Meta. Consume that flag on every other key up
|
||||||
// front: keys handled before the Meta lookup below (arrows, mouse, Enter,
|
// front: keys handled before the Meta lookup below (arrows, mouse, Enter,
|
||||||
// control chords) used to leave it set, turning a later plain key into a
|
// control chords) used to leave it set, turning a later plain key into a
|
||||||
// Meta command (ESC, Left, d => delete word).
|
// Meta command (ESC, Left, d => delete word). KEY_ENTER still sees `meta`
|
||||||
|
// so ESC-Enter can insert a raw newline.
|
||||||
const bool meta = esc_meta && ch != 27;
|
const bool meta = esc_meta && ch != 27;
|
||||||
if (ch != 27)
|
if (ch != 27)
|
||||||
esc_meta = false;
|
esc_meta = false;
|
||||||
@@ -67,7 +68,7 @@ map_key_to_command(const int ch,
|
|||||||
// Some terminals send KEY_ENTER distinct from '\n'/'\r'
|
// Some terminals send KEY_ENTER distinct from '\n'/'\r'
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
k_ctrl_pending = false;
|
k_ctrl_pending = false;
|
||||||
out = {true, CommandId::Newline, "", 0};
|
out = {true, KEnterCommand(meta), "", 0};
|
||||||
return true;
|
return true;
|
||||||
case KEY_MOUSE: {
|
case KEY_MOUSE: {
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
@@ -195,7 +196,7 @@ map_key_to_command(const int ch,
|
|||||||
|
|
||||||
// Meta (ESC-prefixed) keys: backspace, Enter and printable keys use the
|
// Meta (ESC-prefixed) keys: backspace, Enter and printable keys use the
|
||||||
// ESC keymap. Checked before control chords so ESC ^H (meta-backspace) is
|
// ESC keymap. Checked before control chords so ESC ^H (meta-backspace) is
|
||||||
// not taken as C-h, and before Enter so ESC Enter reaches SmartNewline.
|
// not taken as C-h, and before Enter so ESC Enter reaches a raw newline.
|
||||||
// Other control chords after ESC act as themselves.
|
// Other control chords after ESC act as themselves.
|
||||||
const bool is_backspace = (is_keycode && ch == KEY_BACKSPACE) || ch == 127 || ch == CTRL('H');
|
const bool is_backspace = (is_keycode && ch == KEY_BACKSPACE) || ch == 127 || ch == CTRL('H');
|
||||||
const bool meta_key = meta && (is_backspace || (!is_keycode && (ch == '\n' || ch == '\r' || ch >= 0x20)));
|
const bool meta_key = meta && (is_backspace || (!is_keycode && (ch == '\n' || ch == '\r' || ch >= 0x20)));
|
||||||
@@ -315,7 +316,7 @@ map_key_to_command(const int ch,
|
|||||||
if (ch == '\n' || ch == '\r') {
|
if (ch == '\n' || ch == '\r') {
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
k_ctrl_pending = false;
|
k_ctrl_pending = false;
|
||||||
out = {true, CommandId::Newline, "", 0};
|
out = {true, KEnterCommand(false), "", 0};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Backspace in ncurses can be KEY_BACKSPACE or 127
|
// Backspace in ncurses can be KEY_BACKSPACE or 127
|
||||||
|
|||||||
@@ -97,3 +97,25 @@ TEST(KKeymap_EscChords_CanonicalChords)
|
|||||||
|
|
||||||
ASSERT_EQ(KLookupEscCommand('z', id), false);
|
ASSERT_EQ(KLookupEscCommand('z', id), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(KKeymap_Enter_IsSmartNewline)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(KEnterCommand(false), CommandId::SmartNewline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(KKeymap_ShiftEnter_IsNewline)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(KEnterCommand(true), CommandId::Newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(KKeymap_EscEnter_IsNewline)
|
||||||
|
{
|
||||||
|
CommandId id{};
|
||||||
|
ASSERT_TRUE(KLookupEscCommand('\n', id));
|
||||||
|
ASSERT_EQ(id, CommandId::Newline);
|
||||||
|
ASSERT_TRUE(KLookupEscCommand('\r', id));
|
||||||
|
ASSERT_EQ(id, CommandId::Newline);
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ ApplyNordImGuiTheme()
|
|||||||
colors[ImGuiCol_TitleBgCollapsed] = nord1;
|
colors[ImGuiCol_TitleBgCollapsed] = nord1;
|
||||||
|
|
||||||
colors[ImGuiCol_MenuBarBg] = nord1;
|
colors[ImGuiCol_MenuBarBg] = nord1;
|
||||||
colors[ImGuiCol_ScrollbarBg] = nord10;
|
colors[ImGuiCol_ScrollbarBg] = nord0;
|
||||||
colors[ImGuiCol_ScrollbarGrab] = nord3;
|
colors[ImGuiCol_ScrollbarGrab] = nord3;
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = nord2;
|
colors[ImGuiCol_ScrollbarGrabHovered] = nord2;
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = nord1;
|
colors[ImGuiCol_ScrollbarGrabActive] = nord1;
|
||||||
|
|||||||
+1
-1
@@ -155,7 +155,7 @@ ApplyOldBookDarkTheme()
|
|||||||
|
|
||||||
colors[ImGuiCol_FrameBg] = bg1;
|
colors[ImGuiCol_FrameBg] = bg1;
|
||||||
colors[ImGuiCol_FrameBgHovered] = bg2;
|
colors[ImGuiCol_FrameBgHovered] = bg2;
|
||||||
colors[ImGuiCol_FrameBgActive] = fg2;
|
colors[ImGuiCol_FrameBgActive] = bg3;
|
||||||
|
|
||||||
colors[ImGuiCol_TitleBg] = bg1;
|
colors[ImGuiCol_TitleBg] = bg1;
|
||||||
colors[ImGuiCol_TitleBgActive] = bg2;
|
colors[ImGuiCol_TitleBgActive] = bg2;
|
||||||
|
|||||||
Reference in New Issue
Block a user