From: Thomas Walker Lynch Date: Sat, 10 Oct 2026 05:22:09 +0000 (+0000) Subject: . X-Git-Url: https://git.reasoningtechnology.com/?a=commitdiff_plain;h=d43f1d9f33622cec2ccfc7b958233038cc1be1b1;p=Harmony . --- diff --git a/administrator/document/how-to_add-project-dependency.html b/administrator/document/how-to_add-project-dependency.html index 1069c20..327a28c 100644 --- a/administrator/document/how-to_add-project-dependency.html +++ b/administrator/document/how-to_add-project-dependency.html @@ -1,21 +1,119 @@ -#+TITLE: Generic Third-Party Installation Guide -#+AUTHOR: Project Administrator + + + + + How to add a project dependency + + + + + + + + -This project utilizes the Harmony skeleton's `.init` architecture for managing external dependencies. Third-party tools and projects are maintained outside the main repository boundary and linked into the workspace. + -* 1. The Neighbor Directory -Download, clone, or extract the external tool into the same parent directory that contains this project workspace. It must sit as a sibling directory to your current project. +

Project dependencies

-* 2. The Symlink -Navigate to the `$REPO_HOME/shared/linked-project` directory. You will notice a pre-existing symlink named `project` that points to the parent directory of this project. Use that to create a clean symlink to the external tool. +

+ A project dependency is software the project uses but did not author: a language toolchain, a library, a tool, or another project. A dependency is installed outside the project, as a sibling directory of it, and is linked into the project under shared/project-dependency. +

-#+begin_src bash -cd shared/linked-project -ln -s project/ -#+end_src +

+ Getting an arbitrary piece of software working is different every time, so the administrator is free to do whatever a dependency needs inside shared/project-dependency. The skeleton relies on only the few conventions given in the next section. +

-* 3. The Initialization File -Create a configuration file named `.init` inside the `$REPO_HOME/shared/linked-project/` directory. This file is automatically sourced when a project participate enters their role environment using `. setup ` as part of the project setup. Use this file to update the `PATH` or export necessary environment variables needed for using the linked project. +

What the skeleton relies on

-Review existing `.init` files in the directory for structural examples. +
    +
  • project : A link to ../../../, the directory that holds this project and its siblings. It comes with the skeleton. Links to dependencies are made through it, so they are relative and stay correct in every clone.
  • +
  • <name>.init : A bash script that every role setup sources, for every role, each time a person takes on a role. It puts the dependency into the environment, typically by adding to PATH or exporting variables.
  • +
  • <name>.org or <name>.html : Notes on how the dependency was installed, so that each team member can repeat the installation after cloning. Short notes may instead be comments at the top of <name>.init.
  • +
  • <name>.install : Optional. A script that carries out the installation, where it can be automated. A person runs it; setup never does.
  • +
  • .gitignore : Belongs to the administrator. It decides which of the files in the directory are tracked.
  • +
+

+ Files for one dependency share a base name, so that Python.init, Python.org, and the link they describe sit together in a listing. +

+ +

Steps

+ +

Install the dependency beside the project

+

+ Download, clone, or extract the dependency into the directory that holds the project, so that it sits as a sibling of the project directory. Build it there if it needs building. +

+ +

Link it

+

+ Make the link through the project link. The word project in the link target is literal. +

+ + > cd $REPO_HOME/shared/project-dependency + > ln -s project/<dependency directory> <name> + + +

Write the init file

+

+ Write <name>.init in the same directory. Because it runs on every setup for every role, keep it to setting the environment: +

+
    +
  • Make it quick, and safe to run any number of times.
  • +
  • Do not install, build, or download anything from it.
  • +
  • Test that the dependency is present before using it, so that a clone without the dependency still sets up.
  • +
  • Print nothing in normal use. A notice for the administrator role, when the dependency is missing, is fine.
  • +
+

+ Python.init, which comes with the skeleton, is an example: +

+ + if [[ -d "$REPO_HOME/shared/project-dependency/Python-3.12.3/bin" ]]; then + PATH="$REPO_HOME/shared/project-dependency/Python-3.12.3/bin:$PATH" + else + if [[ "$ROLE" == "administrator" ]]; then + echo "Notice: Local Python-3.12.3 bin not found. Using system Python." + fi + fi + + +

Write the installation notes

+

+ Record what was installed, where it came from, and the commands used, in <name>.org, <name>.html, or comments in the init file. A team member who has cloned the project follows these notes to install the dependency, and then recreates the link if it is not tracked. +

+ +

Decide what is tracked

+

+ The skeleton's .gitignore tracks itself, the project link, and files ending in .init, .install, .org, and .html. Everything else in the directory is ignored. To track a dependency's link, so that it arrives with every clone, add a line naming it: +

+ + !<name> + +

+ A tracked link points at nothing until the dependency is installed beside the project, which is why init files test for the dependency before using it. +

+ +

Commit

+

+ Add the init file, the notes, the .gitignore change, and any tracked link, then commit. +

+ +
+ + diff --git a/administrator/document/how-to_release.html b/administrator/document/how-to_release.html index d3d437b..0f33c4a 100644 --- a/administrator/document/how-to_release.html +++ b/administrator/document/how-to_release.html @@ -24,75 +24,75 @@ - - + - +

Prerequisites

- A developer works in the developer branch of the project, and makes use of the build and promote tools to stage release candidates into the $REPO_HOME/consumer directory. The tester then validates the release candidate. This constitutes a cycle of work, developing, promoting candidates, testing, and then further developing. Once the project manager agrees this cycle is complete, the release flow moves to the next step. + A developer works in the developer branch of the project, and makes use of the build and promote tools to stage release candidates into the $REPO_HOME/consumer directory. The tester then validates the release candidate. This constitutes a cycle of work, developing, promoting candidates, testing, and then further developing. Once the project manager agrees this cycle is complete, the release flow moves to the next step.

Make the release branch

- The administrator executes the release. Open a terminal. Enter the project workspace. + The administrator executes the release. Open a terminal. Enter the project workspace.

- + > . setup administrator - +

Switch to the core development branch. Ensure the local repository is current.

- + > git checkout core-developer_branch > git pull - +

Make a new branch for the release. Use the major version number.

- + > git checkout -b release_v<major> - +

Issue management and patching

- Only critical issues receive patches on a release branch. The product manager defines what is critical. If approved, the release team applies the fix directly to the existing release_v<major> branch. + Only critical issues receive patches on a release branch. The product manager defines what is critical. If approved, the release team applies the fix directly to the existing release_v<major> branch.

- The branch name release_v<major> remains static. The code on the branch is updated. The administrator advances the minor release number in the shared/tool/version file. + The branch name release_v<major> remains static. The code on the branch is updated. The administrator advances the minor release number in the shared/tool/version file.

- The administrator tags the new commit with the full version number, such as v<major>.<minor>. Minor versions are edits on the major release branch. They are visible to a person by running the version command. + The administrator tags the new commit with the full version number, such as v<major>.<minor>. Minor versions are edits on the major release branch. They are visible to a person by running the version command.

- The developer must ensure the fix is also ported to the core-developer_branch. This prevents the defect from reappearing in future major releases. + The developer must ensure the fix is also ported to the core-developer_branch. This prevents the defect from reappearing in future major releases.

Tag and push

Tag the release with the exact version number.

- + > git tag -a v<major>.<minor> -m "Release v<major>.<minor>" - +

Push the branch to the remote repository. Push the tags.

- + > git push origin release_v<major> > git push origin --tags - +

Repository default branch

- Set the repository default branch to the new release_v<major> branch on the hosting platform. This ensures a person cloning or pulling the repository receives the most recent major release code by default. + Set the repository default branch to the new release_v<major> branch on the hosting platform. This ensures a person cloning or pulling the repository receives the most recent major release code by default.

Verification

@@ -109,6 +109,6 @@
  • Project Manager: Participates in release issue triage. Assesses impact to the overall project schedule.
  • - +
    diff --git a/administrator/document/install_Python.org b/administrator/document/install_Python.org deleted file mode 100644 index 04d60a6..0000000 --- a/administrator/document/install_Python.org +++ /dev/null @@ -1,38 +0,0 @@ -#+TITLE: Python Installation Guide -#+AUTHOR: Project Administrator - -This project requires a dedicated Python environment. The configuration plugin (`shared/linked-project/Python.init`) was written targeting Python 3.12.3, though the architecture does not rely on any known version-dependent features. - -* 1. Download and Extract -Download the Python source code and extract it as a sibling to the main project directory. Assuming you are at the top level of your project workspace: - -#+begin_src bash -cd ../ -wget https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz -tar -xzf Python-3.12.3.tgz -cd Python-3.12.3 -#+end_src - -* 2. Build the Environment -Compile the Python binaries in place. Setting the installation prefix to the current directory isolates the build, and enabling shared libraries ensures compatibility with C extensions. - -#+begin_src bash -./configure --prefix="$(pwd)" --enable-optimizations --enable-shared -make -j8 -make install -#+end_src - -* 3. Link the Project - -Python-3.12.3 is linked to a Harmony derived project by default. - -See installation_generic.org for details about linking a project, if you want to check the setup. - -If you are installing a different version, then at least the Python-3.12.3 version project linking is there as a good example. - -Project linking is not difficult, make a sym link to `project/`, and then add an init file, that is described in installation_generic.org. The 'project' in the link is literal. - - - - - diff --git a/document/introduction_Harmony.html b/document/introduction_Harmony.html index 4271b0b..e6ea9b4 100644 --- a/document/introduction_Harmony.html +++ b/document/introduction_Harmony.html @@ -260,7 +260,7 @@

    - Currently, our developers write documents directly in HTML using the RT semantic tags. See the RT·Style project and the documentation there. A common approach is to copy another document and the setup.js file, then to type over the top of that other document. + Currently, our developers write documents directly in HTML using the RT semantic tags. See the RT-Style project and the documentation there. A common approach is to copy an existing document while keeping the RT-Style script block in the header intact, then and typing over the contents.

    Untracked directories

    @@ -290,74 +290,82 @@

    The Harmony directory tree

    - 2026-06-23 13:41:45 Z [Harmony:administrator] Thomas_developer@StanleyPark + 2026-10-09 09:22:21 Z [Harmony:administrator] Thomas_developer@Yangming §/home/Thomas/subu_data/developer/project§ > tree Harmony Harmony ├── 0pus_Harmony ├── administrator - │ ├── authored - │ ├── document - │ │ └── setup.js - │ └── tool - │ ├── archive - │ └── setup + │ ├── authored + │ ├── document + │ │ ├── how-to_release.html + │ │ ├── install_generic.org + │ │ └── install_Python.org + │ └── tool + │ ├── archive + │ ├── html_to_v31 + │ ├── new-project + │ ├── RT-Style_header_v5_to_v6 + │ ├── setup + │ └── skeleton_diff ├── consumer - │ └── .gitignore + │ └── ExampleGreet + │ ├── hello + │ └── libHarmony.a ├── developer - │ ├── authored - │ │ └── hello.CLI.c - │ ├── document - │ │ ├── 02_RT_Code_Format.html - │ │ ├── 03_Naming_and_Directory_Conventions.html - │ │ ├── 04_Language_Addenda.html - │ │ └── setup.js - │ ├── experiment - │ ├── made - │ ├── scratchpad - │ └── tool - │ ├── do_all - │ ├── build - │ ├── makefile - │ ├── promote - │ └── setup + │ ├── authored + │ │ └── ExampleGreet.make + │ │ ├── Greeter.lib.c + │ │ ├── hello.CLI.c + │ │ └── Math.lib.c + │ ├── document + │ │ ├── naming_file-and-directory.html + │ │ └── single-file_C-module-and-namespace.html + │ ├── experiment + │ ├── scratchpad + │ └── tool + │ ├── build + │ ├── build_component + │ │ ├── copy + │ │ ├── make + │ │ ├── makefile + │ │ └── sync_engine.py + │ ├── promote + │ └── setup ├── document - │ ├── introduction_Harmony.html - │ ├── role-and-workflow_product-development.html - │ └── setup.js + │ ├── introduction_Harmony.html + │ ├── role-and-workflow_product-development.html + │ ├── role-and-workflow_product-maintenance.html + │ └── writing_tool-script.html ├── LICENSE ├── README.md ├── scratchpad ├── setup ├── shared - │ ├── authored - │ ├── document - │ │ ├── install_generic.org - │ │ ├── install_Python.org - │ │ └── setup.js - │ ├── made - │ ├── dictionary_style-directory.js - │ ├── linked-project - │ │ ├── project -> ../../../ - │ │ ├── Python-3.12.3 -> project/Python-3.12.3 - │ │ ├── Python.init - │ │ ├── RT·Style -> project/RT·Style/consumer - │ │ └── RT·Style.init - │ └── tool - │ ├── scratchpad - │ ├── setup - │ ├── style - │ └── version + │ ├── authored + │ ├── document + │ ├── linked-project + │ │ ├── project -> ../../../ + │ │ ├── Python-3.12.3 -> project/Python-3.12.3 + │ │ └── Python.init + │ └── tool + │ ├── env_to_emacs + │ ├── makefile + │ │ ├── Harmony.mk + │ │ ├── RT_global.h + │ │ └── target_kernel-module.mk + │ ├── PATH.sh + │ ├── RT-formatter + │ ├── RT-formatter.el + │ ├── scratchpad + │ ├── setup + │ └── version └── tester ├── authored - │ └── test_routine.sh - ├── RT_Format - │ ├── RT_Format - │ ├── RT·formatter.el - │ ├── data_test-0.c - │ └── data_test-1.py └── tool └── setup + + 28 directories, 43 files diff --git a/document/writing_tool-script.html b/document/writing_tool-script.html index 181dd63..5942d3f 100644 --- a/document/writing_tool-script.html +++ b/document/writing_tool-script.html @@ -150,7 +150,7 @@

    - A tool does not follow symbolic links to directories. A Harmony project has shared/linked-project/project pointing to ../../../, the directory holding all the projects. Following it would send the walk into every neighboring project and around the loop back into this one. In Python, os.walk does not follow such links unless given followlinks=True, so leave that argument out. + A tool does not follow symbolic links to directories. A Harmony project has shared/project-dependency/project pointing to ../../../, the directory holding all the projects. Following it would send the walk into every neighboring project and around the loop back into this one. In Python, os.walk does not follow such links unless given followlinks=True, so leave that argument out.

    Paths

    diff --git a/shared/linked-project/Python-3.12.3 b/shared/linked-project/Python-3.12.3 deleted file mode 120000 index c2895cf..0000000 --- a/shared/linked-project/Python-3.12.3 +++ /dev/null @@ -1 +0,0 @@ -project/Python-3.12.3 \ No newline at end of file diff --git a/shared/linked-project/Python.init b/shared/linked-project/Python.init deleted file mode 100644 index 2c08a85..0000000 --- a/shared/linked-project/Python.init +++ /dev/null @@ -1,16 +0,0 @@ -# -*- mode: sh; sh-shell: bash; -*- -# init files are bash script - -# Python.init -# -------------------------------------------------------------------------------- -# Ensure the local Python build is prioritized in the PATH. -# The user must establish the Python-3.12.3 symlink for this to activate. - -if [[ -d "$REPO_HOME/shared/linked-project/Python-3.12.3/bin" ]]; then - PATH="$REPO_HOME/shared/linked-project/Python-3.12.3/bin:$PATH" -else - # Optional: Issue a quiet warning for the administrator role - if [[ "$ROLE" == "administrator" ]]; then - echo "Notice: Local Python-3.12.3 bin not found. Using system Python." - fi -fi diff --git a/shared/linked-project/project b/shared/linked-project/project deleted file mode 120000 index 1b20c9f..0000000 --- a/shared/linked-project/project +++ /dev/null @@ -1 +0,0 @@ -../../../ \ No newline at end of file diff --git a/shared/project-dependency/.gitignore b/shared/project-dependency/.gitignore new file mode 100644 index 0000000..a033c31 --- /dev/null +++ b/shared/project-dependency/.gitignore @@ -0,0 +1,11 @@ +# shared/project-dependency/.gitignore +# Tracks the skeleton's parts. Add a ! line for anything else to track, +# such as a dependency's link. +* +!.gitignore +!project +!*.init +!*.install +!*.org +!*.html +!Python-3.12.3 diff --git a/shared/project-dependency/Python-3.12.3 b/shared/project-dependency/Python-3.12.3 new file mode 120000 index 0000000..c2895cf --- /dev/null +++ b/shared/project-dependency/Python-3.12.3 @@ -0,0 +1 @@ +project/Python-3.12.3 \ No newline at end of file diff --git a/shared/project-dependency/Python.init b/shared/project-dependency/Python.init new file mode 100644 index 0000000..eddbaad --- /dev/null +++ b/shared/project-dependency/Python.init @@ -0,0 +1,16 @@ +# -*- mode: sh; sh-shell: bash; -*- +# init files are bash script + +# Python.init +# -------------------------------------------------------------------------------- +# Ensure the local Python build is prioritized in the PATH. +# The user must establish the Python-3.12.3 symlink for this to activate. + +if [[ -d "$REPO_HOME/shared/project-dependency/Python-3.12.3/bin" ]]; then + PATH="$REPO_HOME/shared/project-dependency/Python-3.12.3/bin:$PATH" +else + # Optional: Issue a quiet warning for the administrator role + if [[ "$ROLE" == "administrator" ]]; then + echo "Notice: Local Python-3.12.3 bin not found. Using system Python." + fi +fi diff --git a/shared/project-dependency/Python.org b/shared/project-dependency/Python.org new file mode 100644 index 0000000..a5ba50c --- /dev/null +++ b/shared/project-dependency/Python.org @@ -0,0 +1,38 @@ +#+TITLE: Python Installation Guide +#+AUTHOR: Project Administrator + +This project requires a dedicated Python environment. The configuration plugin (`shared/project-dependency/Python.init`) was written targeting Python 3.12.3, though the architecture does not rely on any known version-dependent features. + +* 1. Download and Extract +Download the Python source code and extract it as a sibling to the main project directory. Assuming you are at the top level of your project workspace: + +#+begin_src bash +cd ../ +wget https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz +tar -xzf Python-3.12.3.tgz +cd Python-3.12.3 +#+end_src + +* 2. Build the Environment +Compile the Python binaries in place. Setting the installation prefix to the current directory isolates the build, and enabling shared libraries ensures compatibility with C extensions. + +#+begin_src bash +./configure --prefix="$(pwd)" --enable-optimizations --enable-shared +make -j8 +make install +#+end_src + +* 3. Link the Project + +Python-3.12.3 is linked to a Harmony derived project by default. + +See administrator/document/how-to_add-project-dependency.html for details about linking a project, if you want to check the setup. + +If you are installing a different version, then at least the Python-3.12.3 version project linking is there as a good example. + +Project linking is not difficult, make a sym link to `project/`, and then add an init file, as described in administrator/document/how-to_add-project-dependency.html. The 'project' in the link is literal. + + + + + diff --git a/shared/project-dependency/project b/shared/project-dependency/project new file mode 120000 index 0000000..1b20c9f --- /dev/null +++ b/shared/project-dependency/project @@ -0,0 +1 @@ +../../../ \ No newline at end of file diff --git a/shared/tool/RT-formatter b/shared/tool/RT-formatter deleted file mode 100644 index 0e57d5a..0000000 --- a/shared/tool/RT-formatter +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env -S python3 -B -# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- -""" -RTfmt — Reasoning Technology code formatter (Predicate Tokenizer) - -Commands: - RTfmt write [--lisp] Format files in place (rewrite originals) - RTfmt copy [--lisp] Save backups as ~ then format originals - RT-formatter pipe [--lisp] Read from stdin, write to stdout - RTfmt self_test Run built-in tests - RTfmt version Show tool version - RTfmt help | --help Show usage -""" - -import sys ,re ,shutil ,os -from typing import List ,Tuple ,Optional ,TextIO - -RTF_VERSION = "0.5.0-predicate" - -def get_usage() -> str: - prog_name = os.path.basename(sys.argv[0]) - return f"""\ -Usage: - {prog_name} write [--lisp] - {prog_name} copy [--lisp] - {prog_name} pipe [--lisp] - {prog_name} self_test - {prog_name} version - {prog_name} help | --help -""" - -# Removed < and > so they are treated as standard CODE operators -BR_OPEN = "([{" -BR_CLOSE = ")]}" -PAIR = dict( zip(BR_OPEN ,BR_CLOSE) ) -REV = dict( zip(BR_CLOSE ,BR_OPEN) ) - -# --------------- Lexer ---------------- - -class RT_Token: - def __init__(self ,kind: str ,text: str): - self.kind = kind - self.text = text - - def __repr__(self): - return f"<{self.kind}:{repr(self.text)}>" - -TOKEN_REGEX = re.compile( - r'(?P//[^\n]*|#[^\n]*|(?s:/\*.*?\*/))' - r'|(?P"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')' - r'|(?P[ \t]+)' - r'|(?P\n)' - r'|(?P,)' - r'|(?P[\[\(\{])' - r'|(?P[\]\)\}])' - r'|(?P[^ \t\n,\[\(\{\]\)\}"\'#/]+|/)' -) - -def tokenize(text: str) -> List[RT_Token]: - tokens = [] - for TM_match in TOKEN_REGEX.finditer(text): - kind = TM_match.lastgroup - text_val = TM_match.group(kind) - tokens.append( RT_Token(kind ,text_val) ) - return tokens - -# --------------- Intelligence API ---------------- - -class TokenStream: - def __init__(self ,tokens: List[RT_Token]): - self.tokens = tokens - - def get_token(self ,index: int) -> Optional[RT_Token]: - if 0 <= index < len(self.tokens): - return self.tokens[index] - return None - - def next_sig_index(self ,index: int) -> Optional[int]: - for TM_i in range(index + 1 ,len(self.tokens)): - if self.tokens[TM_i].kind not in ("SPACE" ,"NEWLINE" ,"COMMENT"): - return TM_i - return None - - def is_first_on_line(self ,index: int) -> bool: - for TM_i in range(index - 1 ,-1 ,-1): - k = self.tokens[TM_i].kind - if k == "NEWLINE": - return True - if k != "SPACE": - return False - return True # Start of file - - def indent_of_line(self ,index: int) -> str: - for TM_i in range(index ,-1 ,-1): - if self.tokens[TM_i].kind == "NEWLINE": - if TM_i + 1 < len(self.tokens) and self.tokens[TM_i + 1].kind == "SPACE": - return self.tokens[TM_i + 1].text - return "" - if self.tokens and self.tokens[0].kind == "SPACE": - return self.tokens[0].text - return "" - - def indent_of_left_match(self ,index: int) -> Optional[str]: - tok = self.get_token(index) - if not tok or tok.kind != "BR_CLOSE": - return None - target_opener = REV[tok.text] - depth = 0 - for TM_i in range(index - 1 ,-1 ,-1): - t = self.tokens[TM_i] - if t.kind == "BR_CLOSE": - depth += 1 - elif t.kind == "BR_OPEN": - if depth > 0: - depth -= 1 - elif t.text == target_opener: - return self.indent_of_line(TM_i) - return None - -# --------------- Rule Engine ---------------- - -def rule_migrate_vertical_commas(stream: TokenStream): - TM_i = 0 - while TM_i < len(stream.tokens): - if stream.tokens[TM_i].kind == "COMMA": - is_trailing = False - next_sig = stream.next_sig_index(TM_i) - if next_sig is not None: - for TM_j in range(TM_i + 1 ,next_sig): - if stream.tokens[TM_j].kind == "NEWLINE": - is_trailing = True - break - - if is_trailing: - comma_tok = stream.tokens.pop(TM_i) - next_sig -= 1 # Shifted because of pop - stream.tokens.insert(next_sig ,comma_tok) - continue - TM_i += 1 - -def rule_format_horizontal_commas(stream: TokenStream): - for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1): - if stream.tokens[TM_i].kind == "COMMA": - if stream.is_first_on_line(TM_i): - continue - - next_tok = stream.get_token(TM_i + 1) - if next_tok and next_tok.kind == "SPACE": - stream.tokens.pop(TM_i + 1) - - prev_tok = stream.get_token(TM_i - 1) - if prev_tok and prev_tok.kind == "SPACE": - if prev_tok.text != " ": - prev_tok.text = " " - else: - stream.tokens.insert(TM_i ,RT_Token("SPACE" ," ")) - -def rule_fix_closing_indent(stream: TokenStream): - for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1): - if stream.tokens[TM_i].kind == "BR_CLOSE" and stream.is_first_on_line(TM_i): - target_indent = stream.indent_of_left_match(TM_i) - if target_indent is not None: - prev = stream.get_token(TM_i - 1) - if prev and prev.kind == "SPACE": - prev.text = target_indent - else: - stream.tokens.insert(TM_i ,RT_Token("SPACE" ,target_indent)) - -def rule_tighten_brackets(stream: TokenStream): - for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1): - if stream.tokens[TM_i].kind == "SPACE" and not stream.is_first_on_line(TM_i): - prev_t = stream.get_token(TM_i - 1) - next_t = stream.get_token(TM_i + 1) - if (prev_t and prev_t.kind == "BR_OPEN") or (next_t and next_t.kind == "BR_CLOSE"): - stream.tokens.pop(TM_i) - -def get_bracket_spans(stream: TokenStream) -> List[Tuple[int ,int]]: - stack = [] - spans = [] - for TM_i ,tok in enumerate(stream.tokens): - if tok.kind == "BR_OPEN": - stack.append( (tok.text ,TM_i) ) - elif tok.kind == "BR_CLOSE": - if stack and REV[tok.text] == stack[-1][0]: - _ ,pos = stack.pop() - if not stack: - spans.append( (pos ,TM_i) ) - return spans - -def rule_pad_outermost(stream: TokenStream ,is_lisp: bool): - if is_lisp: - return - while True: - spans = get_bracket_spans(stream) - changed = False - for TM_start ,TM_end in reversed(spans): - has_inner = False - for TM_k in range(TM_start + 1 ,TM_end): - if stream.tokens[TM_k].kind in ("BR_OPEN" ,"BR_CLOSE"): - has_inner = True - break - - if has_inner: - left_has = (TM_start + 1 < len(stream.tokens)) and stream.tokens[TM_start + 1].kind == "SPACE" - right_has = (TM_end - 1 >= 0) and stream.tokens[TM_end - 1].kind == "SPACE" - if not left_has or not right_has: - if not right_has: - stream.tokens.insert(TM_end ,RT_Token("SPACE" ," ")) - if not left_has: - stream.tokens.insert(TM_start + 1 ,RT_Token("SPACE" ," ")) - changed = True - break - if not changed: - break - -# --------------- Public API ---------------- - -def format_tokens(tokens: List[RT_Token] ,is_lisp: bool) -> str: - stream = TokenStream(tokens) - - rule_migrate_vertical_commas(stream) - rule_format_horizontal_commas(stream) - rule_tighten_brackets(stream) - rule_fix_closing_indent(stream) - rule_pad_outermost(stream ,is_lisp) - - return "".join(t.text for t in stream.tokens) - -def rt_format_text(text: str ,is_lisp: bool) -> str: - tokens = tokenize(text) - return format_tokens(tokens ,is_lisp) - -def rt_format_stream(inp: TextIO ,out: TextIO ,is_lisp: bool) -> None: - text = inp.read() - out.write( rt_format_text(text ,is_lisp) ) - -# --------------- Self-test ---------------- - -def run_self_test() -> bool: - ok = True - def chk(src ,exp): - nonlocal ok - got = rt_format_text(src ,False) - if got != exp: - print("FAIL:\n" + src + "\n=>\n" + got + "\nexpected:\n" + exp) - ok = False - - chk("a,b,c" ,"a ,b ,c") - chk("a , b , c" ,"a ,b ,c") - chk(" ,vertical_arg" ," ,vertical_arg") - - chk("int a=0,\n b=1,\n c=2;" ,"int a=0\n ,b=1\n ,c=2;") - - chk("f ( x )" ,"f(x)") - chk("f(x) + g(y)" ,"f(x) + g(y)") - chk(" {" ," {") - - src = "int g(){int a=0,b=1,c=2; return h(a,b,c);}" - exp = "int g(){ int a=0 ,b=1 ,c=2; return h(a ,b ,c); }" - chk(src ,exp) - - chk("outer( inner(a,b) )" ,"outer( inner(a ,b) )") - - # Operator protection check - chk("for(int TM = 0; TM < count; ++TM)" ,"for(int TM = 0; TM < count; ++TM)") - - print("SELFTEST OK" if ok else "SELFTEST FAILED") - return ok - -# --------------- CLI ---------------- -def write_files(paths: List[str] ,is_lisp: bool) -> int: - for TM_path in paths: - with open(TM_path ,"r" ,encoding="utf-8") as f: - data = f.read() - formatted = rt_format_text(data ,is_lisp) - with open(TM_path ,"w" ,encoding="utf-8") as f: - f.write(formatted) - return 0 - -def copy_files(paths: List[str] ,is_lisp: bool) -> int: - for TM_path in paths: - shutil.copy2(TM_path ,TM_path + "~") - return write_files(paths ,is_lisp) - -def CLI(argv=None) -> int: - args = list(sys.argv[1:] if argv is None else argv) - usage_text = get_usage() - - if not args or args[0] in {"help" ,"--help" ,"-h"}: - print(usage_text) - return 0 - - is_lisp = "--lisp" in args - args = [TM_a for TM_a in args if TM_a != "--lisp"] - - if not args: - return 0 - - cmd = args[0] - rest = args[1:] - - if cmd == "version": - print(RTF_VERSION) - return 0 - if cmd == "self_test": - ok = run_self_test() - return 0 if ok else 1 - if cmd == "pipe": - rt_format_stream(sys.stdin ,sys.stdout ,is_lisp) - return 0 - if cmd == "write": - if not rest: - print("write: missing \n" + usage_text) - return 2 - return write_files(rest ,is_lisp) - if cmd == "copy": - if not rest: - print("copy: missing \n" + usage_text) - return 2 - return copy_files(rest ,is_lisp) - - print(f"Unknown command: {cmd}\n" + usage_text) - return 2 - -if __name__ == "__main__": - sys.exit( CLI() ) diff --git a/shared/tool/RT-formatter.el b/shared/tool/RT-formatter.el deleted file mode 100644 index c0e2c40..0000000 --- a/shared/tool/RT-formatter.el +++ /dev/null @@ -1,22 +0,0 @@ -(defun RT-formatter-buffer () - "Format the current buffer using RTfmt0." - (interactive) - (if (not (executable-find "RT-formatter")) - (message "Error: RTfmt0 executable not found in PATH.") - (let ((temp-buffer (generate-new-buffer " *RTfmt0*")) - (args (list "pipe"))) - (when (derived-mode-p 'emacs-lisp-mode 'lisp-mode) - (setq args (append args (list "--lisp")))) - (unwind-protect - (let ((exit-code (apply #'call-process-region - (point-min) (point-max) - "RT-formatter" - nil temp-buffer nil - args))) - (if (zerop exit-code) - (progn - ;; Applies a non-destructive diff, preserving point and markers natively - (replace-buffer-contents temp-buffer) - (message "RT-formatter formatting successful.")) - (message "RT-formatter failed with exit code %s. Buffer unchanged." exit-code))) - (kill-buffer temp-buffer))))) diff --git a/shared/tool/setup b/shared/tool/setup index d5e3d76..10fb4cd 100644 --- a/shared/tool/setup +++ b/shared/tool/setup @@ -70,7 +70,7 @@ umask 0077 clean_path # Plugin Sourcing: Dynamically load all the linked project configurations - for init_file in "$REPO_HOME/shared/linked-project/"*.init; do + for init_file in "$REPO_HOME/shared/project-dependency/"*.init; do if [[ -f "$init_file" ]]; then source "$init_file" fi