From d01d3b697f8a10f07dfc669e1b1aa93ee46a019c Mon Sep 17 00:00:00 2001 From: niry1 Date: Wed, 10 Jun 2026 12:25:35 +0300 Subject: [PATCH 1/2] Issue #429 - autocomplete defined labels --- manpage | 8 ++-- specs/docs/alu.md | 6 +-- specs/docs/onepage.md | 2 +- specs/src/generate_build_info.py | 11 +++-- specs/src/processing/Config.cc | 10 ++-- specs/src/processing/Config.h | 3 +- specs/src/test/specs-autocomplete.cc | 70 ++++++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 16 deletions(-) diff --git a/manpage b/manpage index 3807d70..1f3fd52 100644 --- a/manpage +++ b/manpage @@ -2302,9 +2302,9 @@ contains the git branch name of the build. May be empty if not available. For ex .p dev-1.0.0 .IP "build-time" 3 -contains the UTC timestamp of when the build was created. Format is +contains the timestamp of when the build was created. Format is .B yyyy-MM-ddTHH:mm:ss. -For example: +It has local time for local builds, and UTC for GitHub builds. For example: .p 2026-06-08T08:22:52 .IP "build-source" 3 @@ -2318,11 +2318,11 @@ contains the build number from GitHub Actions (github.run_number). Empty for loc .IP "build-info" 3 contains a composite string with all build information. For example: .p - Built locally from commit 8bd11da on branch dev-1.0.0 at 2026-06-08T13:01:18 + Built locally from commit 8bd11da on branch dev-1.0.0 at 2026-06-08T13:01:18 local .p or .p - Built on github (build 217) from commit 8bd11da of version 1.0.0 at 2026-06-08T12:40:01 + Built on github (build 217) from commit 8bd11da of version 1.0.0 at 2026-06-08T10:01:18 UTC .p .SH EXAMPLES diff --git a/specs/docs/alu.md b/specs/docs/alu.md index ca3c1c8..373a9fa 100644 --- a/specs/docs/alu.md +++ b/specs/docs/alu.md @@ -120,13 +120,13 @@ Others are `@cols`, which contains the number of columns in the terminal screen, Build information is also available via the following labels: - `@build-commit` — the git commit hash (short form) of the build - `@build-branch` — the git branch name (may be empty) -- `@build-time` — the UTC timestamp when the build was created (format: `yyyy-MM-ddTHH:mm:ss`) +- `@build-time` — the timestamp when the build was created (format: `yyyy-MM-ddTHH:mm:ss`). It's local time for local builds, or UTC for GitHub builds. - `@build-source` — either `local` or `github` - `@build-number` — the GitHub Actions build number (empty for local builds) - `@build-info` — a composite string with all build information, e.g.: ``` - Built locally from commit 8bd11da on branch dev-1.0.0 at 2026-06-08T13:01:18 - Built on github (build 217) from commit 8bd11da of version 1.0.0 at 2026-06-08T12:40:01 + Built locally from commit 8bd11da on branch dev-1.0.0 at 2026-06-08T13:01:18 local + Built on github (build 217) from commit 8bd11da of version 1.0.0 at 2026-06-08T10:01:18 UTC ``` Additionally, the `@@` string stands for the entire input record. When rolling context is in effect (see [Streams and Records](streams.md#rolling-context)), `@@` always refers to the original input record. The `@!` string refers to the current record as affected by `CONTEXT`, which is the same as `@@` when no `CONTEXT` is active. The `@-n` and `@+n` syntax is an alternative to using that is effective within expressions. Note that reading beyond the input with `@+n` or `@-n` does not cause processing to stop, even if a `READSTOP` token is present in the specification. The following three specifications are equivalent: diff --git a/specs/docs/onepage.md b/specs/docs/onepage.md index 3ac2289..1a4c903 100644 --- a/specs/docs/onepage.md +++ b/specs/docs/onepage.md @@ -202,7 +202,7 @@ There are some pre-configured labels that do not need to be explicitly defined: * rows - contains the number of screen rows. * build-commit - contains the git commit hash (short form) of the build * build-branch - contains the git branch name (may be empty) -* build-time - contains the UTC timestamp when the build was created (format: `yyyy-MM-ddTHH:mm:ss`) +* build-time - contains the timestamp when the build was created (format: `yyyy-MM-ddTHH:mm:ss`). It's local time for local builds, or UTC for GitHub builds. * build-source - contains either `local` or `github` * build-number - contains the GitHub Actions build number (empty for local builds) * build-info - contains a composite string with all build information diff --git a/specs/src/generate_build_info.py b/specs/src/generate_build_info.py index 567d396..32a2ade 100644 --- a/specs/src/generate_build_info.py +++ b/specs/src/generate_build_info.py @@ -55,16 +55,19 @@ def run_git(name, args): if build_branch: report_success("SPECS_BUILD_BRANCH (from SPECS_BRANCH env)", build_branch) -# Get UTC build time -build_time = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S") -report_success("SPECS_BUILD_TIME", build_time) - # Get build source and number from environment build_source = os.environ.get("SPECS_BUILD_SOURCE", "local") report_success("SPECS_BUILD_SOURCE", build_source) build_number = os.environ.get("SPECS_BUILD_NUMBER", "") report_success("SPECS_BUILD_NUMBER", build_number) +# Get UTC build time +if build_source == "local": + build_time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") +else: + build_time = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S") +report_success("SPECS_BUILD_TIME", build_time) + # Write the header file with open("utils/build_info.h", "w") as f: f.write('#define SPECS_BUILD_COMMIT "{}"\n'.format(build_commit)) diff --git a/specs/src/processing/Config.cc b/specs/src/processing/Config.cc index a08d9f4..ca62593 100644 --- a/specs/src/processing/Config.cc +++ b/specs/src/processing/Config.cc @@ -148,7 +148,7 @@ static std::string getTerminalRowsAndColumns(bool bGetRows) } -void readConfigurationFile() +void readConfigurationFile(useKeyValueCB cb) { std::string line; unsigned int lineCounter = 0; @@ -194,7 +194,11 @@ void readConfigurationFile() value = line.substr(idx2, idx-idx2); } - useKeyValue(key, value); + if (cb) { + (*cb)(key, value); + } else { + useKeyValue(key, value); + } } } else { } @@ -241,7 +245,7 @@ void readConfigurationFile() } } } - build_info += " at " + ExternalLiterals["build-time"]; + build_info += " at " + ExternalLiterals["build-time"] + (ExternalLiterals["build-source"] == "github" ? " UTC" : " local"); ExternalLiterals["build-info"] = build_info; } diff --git a/specs/src/processing/Config.h b/specs/src/processing/Config.h index 85da620..51eda5d 100644 --- a/specs/src/processing/Config.h +++ b/specs/src/processing/Config.h @@ -61,7 +61,8 @@ CONFIG_PARAMS #define EXTERNAL_FUNC_ERR_ZERO "zero" #define EXTERNAL_FUNC_ERR_NULLSTR "nullstr" -void readConfigurationFile(); +typedef void (*useKeyValueCB)(std::string& key, std::string& value); +void readConfigurationFile(useKeyValueCB cb = nullptr); bool configSpecLiteralExists(std::string& key); diff --git a/specs/src/test/specs-autocomplete.cc b/specs/src/test/specs-autocomplete.cc index ead92ea..3d695e3 100644 --- a/specs/src/test/specs-autocomplete.cc +++ b/specs/src/test/specs-autocomplete.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "processing/Config.h" @@ -7,6 +8,26 @@ typedef std::vector StringVector; +StringVector SystemDefinedLabels = { + "@version", + "@cols", + "@rows", + "@python", + "@platform", + "@build-commit", + "@build-branch", + "@build-time", + "@build-source", + "@build-number", + "@build-info" +}; + +static void AddToSystemDefineLabels(std::string& key, std::string& value) +{ + key.pop_back(); // remove the final colon + SystemDefinedLabels.push_back("@" + key); +} + void GetFilesByPrefix(StringVector& sv, const char* path, std::string& prefix) { std::filesystem::path specPath(path); @@ -35,8 +56,32 @@ static void getFilenameVector(StringVector& sv, std::string& incomplete, std::st } } +int CompleteUncertain_SystemLabels(std::string& incomplete) +{ + readConfigurationFile(AddToSystemDefineLabels); + StringVector vec; + for (auto s : SystemDefinedLabels) { + if (0==s.compare(0, incomplete.size(), incomplete)) { + vec.push_back(s); + } + } + + // sort the vector + std::sort(vec.begin(), vec.end()); + + for (auto s : vec) { + std::cout << s << "\n"; + } + + return 0; +} + int CompleteUncertain(std::string& incomplete, std::string& prevToken, std::string& line) { + if ('@'==incomplete[0]) { + return CompleteUncertain_SystemLabels(incomplete); + } + StringVector sv; getFilenameVector(sv, incomplete, prevToken); @@ -48,8 +93,33 @@ int CompleteUncertain(std::string& incomplete, std::string& prevToken, std::stri return 0; } +int CompleteIfUnambiguous_SystemLabels(std::string& incomplete) +{ + readConfigurationFile(AddToSystemDefineLabels); + std::string res; + for (auto s : SystemDefinedLabels) { + if (0==s.compare(0, incomplete.size(), incomplete)) { + if (res.empty()) { // First match + res = s; + } else { // not-first match + // trim non-matching characters + while (s.compare(0,res.size(), res)) { + res.pop_back(); + } + } + } + } + + std::cout << res; + return 0; +} + int CompleteIfUnambiguous(std::string& incomplete, std::string& prevToken, std::string& line) { + if ('@'==incomplete[0]) { + return CompleteIfUnambiguous_SystemLabels(incomplete); + } + StringVector sv; getFilenameVector(sv, incomplete, prevToken); From b7d30c3103ac868c51d4a597094d5c84e6529d2d Mon Sep 17 00:00:00 2001 From: niry1 Date: Wed, 10 Jun 2026 13:17:30 +0300 Subject: [PATCH 2/2] Issue #429 - improve examples in manpage --- manpage | 133 +++++++++++++++++++++----------------------------------- 1 file changed, 49 insertions(+), 84 deletions(-) diff --git a/manpage b/manpage index 1f3fd52..9dd9849 100644 --- a/manpage +++ b/manpage @@ -2328,103 +2328,68 @@ or .SH EXAMPLES `ls -l` yields this: - total 352 - -rw-r--r--@ 1 ynir admin 574 Aug 25 2009 Makefile - -rw-r--r--@ 1 ynir admin 3542 Nov 23 00:21 README - -rw-r--r--@ 1 ynir admin 362 Nov 19 08:31 conversion.h - -rw-r--r-- 1 ynir admin 984 Nov 11 17:45 ls.txt - -rw-r--r--@ 1 ynir admin 2233 Nov 23 00:03 main.cc - -rw-r--r-- 1 ynir admin 9412 Nov 23 00:11 main.o - -rw-r--r--@ 1 ynir admin 6567 Nov 23 00:09 spec_build.cc - -rw-r--r-- 1 ynir admin 16776 Nov 23 00:11 spec_build.o - -rw-r--r--@ 1 ynir admin 5494 Nov 19 08:30 spec_convert.cc - -rw-r--r-- 1 ynir admin 17004 Nov 23 00:11 spec_convert.o - -rw-r--r--@ 1 ynir admin 11419 Nov 23 00:10 spec_params.cc - -rw-r--r-- 1 ynir admin 21080 Nov 23 00:11 spec_params.o - -rw-r--r--@ 1 ynir admin 375 Nov 11 09:29 spec_vars.cc - -rw-r--r-- 1 ynir admin 4800 Nov 23 00:11 spec_vars.o - -rwxr-xr-x 1 ynir admin 36740 Nov 23 00:11 specs - -rw-r--r--@ 1 ynir admin 1547 Nov 23 00:10 specs.h + total 96 + -rw-rw-r-- 1 sio sio 16432 Jun 1 12:49 dataField.cc + -rw-rw-r-- 1 sio sio 6187 Jun 4 12:16 InputPart.cc + -rw-rw-r-- 1 sio sio 11717 Jun 4 12:16 item.h + -rw-rw-r-- 1 sio sio 35974 Jun 4 12:16 specItems.cc + -rw-rw-r-- 1 sio sio 1144 Jun 4 12:16 specItems.h + -rw-rw-r-- 1 sio sio 13953 Jun 1 12:49 splitItem.cc Let's run it though a spec: - ls -l | specs 12-* 1 redo w2 1 w4 d2x 8.8 r w8 17 + ls -l | specs 12-* 1 REDO IF "wordcount()>=8" THEN w2 1 w4 d2x 8.8 RIGHT w8 17 The first spec unit converts it to this: - 1 ynir admin 574 Aug 25 2009 Makefile - 1 ynir admin 3542 Nov 23 00:21 README - 1 ynir admin 362 Nov 19 08:31 conversion.h - 1 ynir admin 984 Nov 11 17:45 ls.txt - 1 ynir admin 2233 Nov 23 00:03 main.cc - 1 ynir admin 9412 Nov 23 00:11 main.o - 1 ynir admin 6567 Nov 23 00:09 spec_build.cc - 1 ynir admin 16776 Nov 23 00:11 spec_build.o - 1 ynir admin 5494 Nov 19 08:30 spec_convert.cc - 1 ynir admin 17004 Nov 23 00:11 spec_convert.o - 1 ynir admin 11419 Nov 23 00:10 spec_params.cc - 1 ynir admin 21080 Nov 23 00:11 spec_params.o - 1 ynir admin 375 Nov 11 09:29 spec_vars.cc - 1 ynir admin 4800 Nov 23 00:11 spec_vars.o - 1 ynir admin 36740 Nov 23 00:11 specs - 1 ynir admin 1547 Nov 23 00:10 specs.h - -Then after the redo, we get this: - - ynir 23e Makefile - ynir dd6 README - ynir 16a conversion.h - ynir 3d8 ls.txt - ynir 8b9 main.cc - ynir 24c4 main.o - ynir 19a7 spec_build.cc - ynir 4188 spec_build.o - ynir 1576 spec_convert.cc - ynir 426c spec_convert.o - ynir 2c9b spec_params.cc - ynir 5258 spec_params.o - ynir eae spec_vars.cc - ynir 12c0 spec_vars.o - ynir 8f84 specs - ynir 60b specs.h - + 1 sio sio 16432 Jun 1 12:49 dataField.cc + 1 sio sio 6187 Jun 4 12:16 InputPart.cc + 1 sio sio 11717 Jun 4 12:16 item.h + 1 sio sio 35974 Jun 4 12:16 specItems.cc + 1 sio sio 1144 Jun 4 12:16 specItems.h + 1 sio sio 13953 Jun 1 12:49 splitItem.cc + +Then after the REDO arm, we get this: + + sio 4030 dataField.cc + sio 182b InputPart.cc + sio 2dc5 item.h + sio 8c86 specItems.cc + sio 478 specItems.h + sio 3681 splitItem.cc Alternatively, let's arrange this on multiple lines: - ls -l | specs w9 1 write "Owner:" 3 w3 10 write "Size:" 3 w5 10-20 r - - Makefile - Owner: ynir - Size: 574 - README - Owner: ynir - Size: 5834 - conversion.h - Owner: ynir - Size: 362 - list.txt - Owner: ynir - Size: 978 - ls.txt - Owner: ynir - Size: 984 - main.cc - Owner: ynir - Size: 2233 - main.o - Owner: ynir - Size: 9412 + specs -C "ls -l" w9 1 write "Owner:" 3 w3 10 write "Size:" 3 w5 10-20 r + + Owner: + Size: r + dataField.cc + Owner: sio + Size: 16432 r + InputPart.cc + Owner: sio + Size: 6187 r + item.h + Owner: sio + Size: 11717 r + specItems.cc + Owner: sio + Size: 35974 r + specItems.h + Owner: sio + Size: 1144 r + splitItem.cc + Owner: sio + Size: 13953 r Finally, let's make our own version of the multi-column display: - ls -l | specs w9 1 read w9 26 read w9 51 - Makefile README - conversion.h main.cc main.o - spec_build.cc spec_build.o spec_convert.cc - spec_convert.o spec_params.cc spec_params.o - spec_vars.cc spec_vars.o specs - specs.h + specs -C "ls -l" w9 1 read w9 26 read w9 51 + dataField.cc InputPart.cc + item.h specItems.cc specItems.h + splitItem.cc .SH SEE ALSO sed(1), awk(1)