textual-code 0.0.2__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- textual_code-0.1.1/.devcontainer/Dockerfile +85 -0
- textual_code-0.1.1/.devcontainer/devcontainer.json +26 -0
- textual_code-0.1.1/.devcontainer/docker-compose.yml +23 -0
- textual_code-0.1.1/.devcontainer/ensure-ai-symlinks.sh +51 -0
- textual_code-0.1.1/.devcontainer/qmd-config/index.yml +7 -0
- textual_code-0.1.1/.dockerignore +34 -0
- textual_code-0.1.1/.editorconfig +17 -0
- textual_code-0.1.1/.github/workflows/release.yml +49 -0
- textual_code-0.1.1/.gitignore +29 -0
- {textual_code-0.0.2 → textual_code-0.1.1}/.pre-commit-config.yaml +2 -0
- textual_code-0.1.1/.textual-code.toml +6 -0
- textual_code-0.1.1/CHANGELOG.md +47 -0
- textual_code-0.1.1/CLAUDE.md +56 -0
- textual_code-0.1.1/PKG-INFO +117 -0
- textual_code-0.1.1/README.md +92 -0
- textual_code-0.1.1/docs/features/config.md +391 -0
- textual_code-0.1.1/docs/features/editor.md +287 -0
- textual_code-0.1.1/docs/features/index.md +33 -0
- textual_code-0.1.1/docs/features/internals.md +124 -0
- textual_code-0.1.1/docs/features/ui.md +249 -0
- textual_code-0.1.1/docs/features/workspace.md +341 -0
- textual_code-0.1.1/docs/features.md +5 -0
- textual_code-0.1.1/docs/settings-guide.md +116 -0
- textual_code-0.1.1/docs/testing-guide.md +212 -0
- {textual_code-0.0.2 → textual_code-0.1.1}/pyproject.toml +21 -1
- textual_code-0.1.1/scripts/build-devcontainer.sh +89 -0
- textual_code-0.1.1/scripts/check-language.sh +134 -0
- textual_code-0.1.1/scripts/check-licenses.sh +127 -0
- textual_code-0.1.1/scripts/download-libs-docs.sh +156 -0
- textual_code-0.1.1/scripts/kill-devconatiner.sh +73 -0
- textual_code-0.1.1/scripts/run-devcontainer.sh +271 -0
- textual_code-0.1.1/src/textual_code/__init__.py +82 -0
- textual_code-0.1.1/src/textual_code/app.py +1557 -0
- textual_code-0.1.1/src/textual_code/commands.py +160 -0
- textual_code-0.1.1/src/textual_code/config.py +151 -0
- textual_code-0.1.1/src/textual_code/grammars/c.scm +85 -0
- textual_code-0.1.1/src/textual_code/grammars/cpp.scm +81 -0
- textual_code-0.1.1/src/textual_code/grammars/dockerfile.scm +60 -0
- textual_code-0.1.1/src/textual_code/grammars/kotlin.scm +203 -0
- textual_code-0.1.1/src/textual_code/grammars/lua.scm +105 -0
- textual_code-0.1.1/src/textual_code/grammars/make.scm +109 -0
- textual_code-0.1.1/src/textual_code/grammars/php.scm +128 -0
- textual_code-0.1.1/src/textual_code/grammars/ruby.scm +158 -0
- textual_code-0.1.1/src/textual_code/grammars/tsx.scm +39 -0
- textual_code-0.1.1/src/textual_code/grammars/typescript.scm +39 -0
- textual_code-0.1.1/src/textual_code/modals.py +1178 -0
- textual_code-0.1.1/src/textual_code/search.py +225 -0
- textual_code-0.1.1/src/textual_code/style.tcss +901 -0
- textual_code-0.1.1/src/textual_code/utils.py +15 -0
- textual_code-0.1.1/src/textual_code/widgets/code_editor.py +1925 -0
- textual_code-0.1.1/src/textual_code/widgets/draggable_tabs_content.py +597 -0
- textual_code-0.1.1/src/textual_code/widgets/explorer.py +684 -0
- textual_code-0.1.1/src/textual_code/widgets/find_replace_bar.py +163 -0
- textual_code-0.1.1/src/textual_code/widgets/main_view.py +1353 -0
- textual_code-0.1.1/src/textual_code/widgets/markdown_preview.py +77 -0
- textual_code-0.1.1/src/textual_code/widgets/multi_cursor_text_area.py +965 -0
- textual_code-0.1.1/src/textual_code/widgets/sidebar.py +140 -0
- textual_code-0.1.1/src/textual_code/widgets/split_container.py +45 -0
- textual_code-0.1.1/src/textual_code/widgets/split_resize_handle.py +107 -0
- textual_code-0.1.1/src/textual_code/widgets/split_tree.py +252 -0
- textual_code-0.1.1/src/textual_code/widgets/workspace_search.py +239 -0
- textual_code-0.1.1/tests/__init__.py +0 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_app_with_file.svg +229 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_change_language_modal.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_change_syntax_theme_modal.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_change_ui_theme_modal.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_change_word_wrap_modal.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_delete_modal.svg +237 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_discard_and_reload_modal.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_dockerfile_highlighting.svg +229 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_drop_target_edge_highlight.svg +234 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_drop_target_highlight.svg +234 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_empty_app.svg +223 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_encoding_modal_with_save_level.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_explorer_dim_hidden_files.svg +224 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_explorer_git_status.svg +226 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_explorer_hidden_files_visible.svg +224 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_find_bar_open.svg +235 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_footer_encoding_modal_no_save_level.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_footer_indent_modal_no_save_level.svg +240 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_footer_line_ending_modal_no_save_level.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_footer_path_truncation.svg +226 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_goto_line_modal.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_indent_modal_with_save_level.svg +234 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_line_ending_modal_with_save_level.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_markdown_preview_open.svg +224 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_multi_cursor.svg +229 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_multiple_tabs.svg +230 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_narrow_sidebar_icon_only.svg +233 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_new_editor_tab.svg +225 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_overwrite_confirm_modal.svg +235 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_readme_preview.svg +235 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_rebind_key_screen.svg +232 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_replace_bar_open.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_save_as_modal.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_show_shortcuts_screen.svg +230 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_sidebar_custom_width.svg +223 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_sidebar_resize_modal.svg +234 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_sidebar_search_tab.svg +233 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_split_left_view_open.svg +230 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_split_resize_modal.svg +240 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_split_view_open.svg +230 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_tab_dragging_highlight.svg +231 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_tab_reorder_active_indicator.svg +230 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_tab_reorder_right_indicator.svg +229 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_unsaved_change_modal.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_unsaved_marker.svg +229 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_unsaved_quit_modal.svg +236 -0
- textual_code-0.1.1/tests/__snapshots__/test_snapshots/test_snapshot_workspace_search_results.svg +239 -0
- textual_code-0.1.1/tests/__snapshots__/test_vertical_split/test_vertical_split_snapshot.svg +230 -0
- textual_code-0.1.1/tests/conftest.py +179 -0
- textual_code-0.1.1/tests/test_app.py +373 -0
- textual_code-0.1.1/tests/test_binary_file.py +116 -0
- textual_code-0.1.1/tests/test_cli.py +47 -0
- textual_code-0.1.1/tests/test_click_selection.py +253 -0
- textual_code-0.1.1/tests/test_clipboard.py +135 -0
- textual_code-0.1.1/tests/test_code_editor.py +796 -0
- textual_code-0.1.1/tests/test_command_shortcuts.py +173 -0
- textual_code-0.1.1/tests/test_copy_path.py +183 -0
- textual_code-0.1.1/tests/test_cross_split_drag.py +1122 -0
- textual_code-0.1.1/tests/test_cursor_btn.py +165 -0
- textual_code-0.1.1/tests/test_delete_with_palette.py +164 -0
- textual_code-0.1.1/tests/test_dim_gitignored.py +333 -0
- textual_code-0.1.1/tests/test_dim_hidden_files.py +155 -0
- textual_code-0.1.1/tests/test_directional_leaf.py +253 -0
- textual_code-0.1.1/tests/test_draggable_tabs_content.py +546 -0
- textual_code-0.1.1/tests/test_editor_defaults.py +311 -0
- textual_code-0.1.1/tests/test_editorconfig.py +953 -0
- textual_code-0.1.1/tests/test_encoding.py +563 -0
- textual_code-0.1.1/tests/test_explorer_auto_refresh.py +430 -0
- textual_code-0.1.1/tests/test_explorer_delete.py +187 -0
- textual_code-0.1.1/tests/test_explorer_highlight.py +196 -0
- textual_code-0.1.1/tests/test_file_watcher.py +623 -0
- textual_code-0.1.1/tests/test_find.py +708 -0
- textual_code-0.1.1/tests/test_find_replace_bar.py +397 -0
- textual_code-0.1.1/tests/test_git_status.py +340 -0
- textual_code-0.1.1/tests/test_global_footer.py +292 -0
- textual_code-0.1.1/tests/test_hidden_files.py +180 -0
- textual_code-0.1.1/tests/test_indent.py +741 -0
- textual_code-0.1.1/tests/test_language_extensions.py +117 -0
- textual_code-0.1.1/tests/test_light_app.py +60 -0
- textual_code-0.1.1/tests/test_line_ending.py +505 -0
- textual_code-0.1.1/tests/test_main_view.py +877 -0
- textual_code-0.1.1/tests/test_markdown_preview.py +512 -0
- textual_code-0.1.1/tests/test_modals.py +843 -0
- textual_code-0.1.1/tests/test_move_line.py +374 -0
- textual_code-0.1.1/tests/test_move_tab_directional.py +269 -0
- textual_code-0.1.1/tests/test_multi_cursor.py +1318 -0
- textual_code-0.1.1/tests/test_no_italic_extension.py +132 -0
- textual_code-0.1.1/tests/test_open_file_command.py +68 -0
- textual_code-0.1.1/tests/test_open_settings.py +89 -0
- textual_code-0.1.1/tests/test_panel_focus.py +79 -0
- textual_code-0.1.1/tests/test_path_display_mode.py +169 -0
- textual_code-0.1.1/tests/test_recursive_split.py +463 -0
- textual_code-0.1.1/tests/test_redo.py +59 -0
- textual_code-0.1.1/tests/test_regex_search.py +447 -0
- textual_code-0.1.1/tests/test_reorder_tab.py +251 -0
- textual_code-0.1.1/tests/test_replace.py +675 -0
- textual_code-0.1.1/tests/test_responsive_labels.py +127 -0
- textual_code-0.1.1/tests/test_select_all_from_bar.py +289 -0
- textual_code-0.1.1/tests/test_select_all_occurrences.py +386 -0
- textual_code-0.1.1/tests/test_select_next_occurrence.py +349 -0
- textual_code-0.1.1/tests/test_shortcuts_panel.py +273 -0
- textual_code-0.1.1/tests/test_sidebar_drag_resize.py +151 -0
- textual_code-0.1.1/tests/test_sidebar_resize.py +273 -0
- textual_code-0.1.1/tests/test_sidebar_width.py +220 -0
- textual_code-0.1.1/tests/test_snapshots.py +942 -0
- textual_code-0.1.1/tests/test_split_container.py +131 -0
- textual_code-0.1.1/tests/test_split_drag_resize.py +172 -0
- textual_code-0.1.1/tests/test_split_resize.py +305 -0
- textual_code-0.1.1/tests/test_split_tree.py +402 -0
- textual_code-0.1.1/tests/test_split_view.py +1075 -0
- textual_code-0.1.1/tests/test_syntax_theme.py +287 -0
- textual_code-0.1.1/tests/test_tab_drag.py +288 -0
- textual_code-0.1.1/tests/test_ui_theme.py +234 -0
- textual_code-0.1.1/tests/test_vertical_split.py +118 -0
- textual_code-0.1.1/tests/test_word_wrap.py +180 -0
- textual_code-0.1.1/tests/test_workspace_replace.py +228 -0
- textual_code-0.1.1/tests/test_workspace_search.py +672 -0
- textual_code-0.1.1/uv.lock +1547 -0
- textual_code-0.0.2/.devcontainer.json +0 -19
- textual_code-0.0.2/.dockerignore +0 -2
- textual_code-0.0.2/.github/workflows/release.yml +0 -21
- textual_code-0.0.2/.gitignore +0 -2
- textual_code-0.0.2/CHANGELOG.md +0 -17
- textual_code-0.0.2/Dockerfile.dev +0 -21
- textual_code-0.0.2/PKG-INFO +0 -175
- textual_code-0.0.2/README.md +0 -154
- textual_code-0.0.2/docker-compose.dev.yml +0 -9
- textual_code-0.0.2/docs/preview.svg +0 -285
- textual_code-0.0.2/src/textual_code/__init__.py +0 -10
- textual_code-0.0.2/src/textual_code/app.py +0 -719
- textual_code-0.0.2/src/textual_code/modals.py +0 -123
- textual_code-0.0.2/src/textual_code/style.tcss +0 -160
- textual_code-0.0.2/src/textual_code/utils.py +0 -21
- textual_code-0.0.2/uv.lock +0 -938
- {textual_code-0.0.2 → textual_code-0.1.1}/.python-version +0 -0
- {textual_code-0.0.2 → textual_code-0.1.1}/.vscode/settings.json +0 -0
- {textual_code-0.0.2 → textual_code-0.1.1}/Dockerfile +0 -0
- {textual_code-0.0.2 → textual_code-0.1.1}/docker-compose.yml +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
FROM ubuntu:24.04 AS base
|
|
2
|
+
|
|
3
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
4
|
+
|
|
5
|
+
# install basic packages
|
|
6
|
+
RUN apt-get update && apt-get upgrade -y && apt-get install -y --fix-broken && apt-get install -y --no-install-recommends \
|
|
7
|
+
build-essential \
|
|
8
|
+
ca-certificates \
|
|
9
|
+
curl \
|
|
10
|
+
git \
|
|
11
|
+
locales \
|
|
12
|
+
ssh \
|
|
13
|
+
sudo \
|
|
14
|
+
vim \
|
|
15
|
+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
|
16
|
+
|
|
17
|
+
RUN locale-gen en_US.UTF-8
|
|
18
|
+
|
|
19
|
+
ARG USER_UID=1000
|
|
20
|
+
ARG USER_GID=1000
|
|
21
|
+
|
|
22
|
+
RUN (groupadd --gid $USER_GID appuser || true) \
|
|
23
|
+
&& (useradd --uid $USER_UID --gid $USER_GID -m appuser -s /bin/bash || true) \
|
|
24
|
+
&& export USERNAME=$(getent passwd $USER_UID | cut -d: -f1) \
|
|
25
|
+
&& echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \
|
|
26
|
+
&& chmod 0440 /etc/sudoers.d/$USERNAME
|
|
27
|
+
|
|
28
|
+
RUN mkdir -p /project \
|
|
29
|
+
&& chown $USER_UID:$USER_GID /project
|
|
30
|
+
|
|
31
|
+
# set LANG env variable
|
|
32
|
+
USER $USER_UID
|
|
33
|
+
RUN echo 'export LANG="en_US.UTF-8"' >> ~/.bashrc \
|
|
34
|
+
&& echo 'export LC_ALL="en_US.UTF-8"' >> ~/.bashrc \
|
|
35
|
+
&& echo 'export NODE_LLAMA_CPP_CMAKE_OPTION_GGML_CUDA=OFF' >> ~/.bashrc
|
|
36
|
+
|
|
37
|
+
FROM base AS tools
|
|
38
|
+
|
|
39
|
+
# install lazygit
|
|
40
|
+
USER root
|
|
41
|
+
RUN export LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*') \
|
|
42
|
+
&& export ARCH=$(dpkg --print-architecture) \
|
|
43
|
+
&& if [ "$ARCH" = "amd64" ]; then export LAZYGIT_ARCH="x86_64"; elif [ "$ARCH" = "arm64" ]; then export LAZYGIT_ARCH="arm64"; else export LAZYGIT_ARCH="$ARCH"; fi \
|
|
44
|
+
&& curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_${LAZYGIT_ARCH}.tar.gz" \
|
|
45
|
+
&& tar xf lazygit.tar.gz lazygit \
|
|
46
|
+
&& install lazygit -D -t /usr/local/bin/ \
|
|
47
|
+
&& rm -rf lazygit.tar.gz lazygit
|
|
48
|
+
|
|
49
|
+
FROM tools AS dev
|
|
50
|
+
|
|
51
|
+
### PROJECT-SPECIFIC SETUP BEGIN
|
|
52
|
+
|
|
53
|
+
# install dependencies
|
|
54
|
+
USER root
|
|
55
|
+
# shellcheck is for linting shell scripts
|
|
56
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
57
|
+
shellcheck \
|
|
58
|
+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
|
59
|
+
|
|
60
|
+
# install uv
|
|
61
|
+
USER $USER_UID
|
|
62
|
+
COPY --from=ghcr.io/astral-sh/uv:0.10.2 /uv /uvx /bin/
|
|
63
|
+
ENV UV_COMPILE_BYTECODE=1
|
|
64
|
+
ENV UV_LINK_MODE=copy
|
|
65
|
+
ENV UV_CACHE_DIR=/project/.devcontainer/uv/cache
|
|
66
|
+
ENV UV_PYTHON_INSTALL_DIR=/project/.devcontainer/uv/python
|
|
67
|
+
ENV UV_PYTHON_BIN_DIR=/project/.devcontainer/uv/python-bin
|
|
68
|
+
|
|
69
|
+
# install python using uv
|
|
70
|
+
USER $USER_UID
|
|
71
|
+
RUN uv python install 3.12 --default \
|
|
72
|
+
&& echo 'export PATH="/project/.devcontainer/uv/python-bin:$PATH"' >> ~/.bashrc \
|
|
73
|
+
&& export PATH="/project/.devcontainer/uv/python-bin:$PATH"
|
|
74
|
+
|
|
75
|
+
# set TERM and COLORTERM env variable for correct color rendering in textual
|
|
76
|
+
USER $USER_UID
|
|
77
|
+
RUN echo 'export TERM="xterm-256color"' >> ~/.bashrc \
|
|
78
|
+
&& echo 'export COLORTERM="truecolor"' >> ~/.bashrc \
|
|
79
|
+
&& export TERM="xterm-256color" \
|
|
80
|
+
&& export COLORTERM="truecolor"
|
|
81
|
+
|
|
82
|
+
### PROJECT-SPECIFIC SETUP END
|
|
83
|
+
|
|
84
|
+
USER $USER_UID
|
|
85
|
+
WORKDIR /project
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "textual-code-devcontainer",
|
|
3
|
+
"dockerComposeFile": "docker-compose.yml",
|
|
4
|
+
"service": "textual-code-devcontainer-app",
|
|
5
|
+
"workspaceFolder": "/project",
|
|
6
|
+
"remoteUser": "1000", // uid of the user in the container, typically a non-root user
|
|
7
|
+
"postCreateCommand": "/project/.devcontainer/ensure-ai-symlinks.sh",
|
|
8
|
+
"customizations": {
|
|
9
|
+
"vscode": {
|
|
10
|
+
"settings": {
|
|
11
|
+
"window.autoDetectColorScheme": true,
|
|
12
|
+
"workbench.preferredDarkColorTheme": "One Dark Pro",
|
|
13
|
+
"workbench.preferredLightColorTheme": "Visual Studio Light"
|
|
14
|
+
},
|
|
15
|
+
"extensions": [
|
|
16
|
+
"Anthropic.claude-code",
|
|
17
|
+
"astral-sh.ty",
|
|
18
|
+
"charliermarsh.ruff",
|
|
19
|
+
"GitHub.copilot",
|
|
20
|
+
"mhutchie.git-graph",
|
|
21
|
+
"ms-python.python",
|
|
22
|
+
"Textualize.textual-syntax-highlighter"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: textual-code-devcontainer
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
textual-code-devcontainer-app:
|
|
5
|
+
build:
|
|
6
|
+
context: .
|
|
7
|
+
dockerfile: Dockerfile
|
|
8
|
+
restart: "no"
|
|
9
|
+
command: sleep infinity
|
|
10
|
+
init: true
|
|
11
|
+
volumes:
|
|
12
|
+
- ../:/project
|
|
13
|
+
environment:
|
|
14
|
+
- CLAUDE_CONFIG_DIR=/home/appuser/.claude
|
|
15
|
+
env_file:
|
|
16
|
+
- path: ../.env
|
|
17
|
+
required: false
|
|
18
|
+
logging:
|
|
19
|
+
driver: "json-file"
|
|
20
|
+
options:
|
|
21
|
+
max-size: "10m"
|
|
22
|
+
max-file: "100"
|
|
23
|
+
compress: "true"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Ensure AI tool directories and files exist in devcontainer
|
|
4
|
+
# This script is called during devcontainer post-create phase
|
|
5
|
+
|
|
6
|
+
set -eu
|
|
7
|
+
|
|
8
|
+
# Define base paths
|
|
9
|
+
DEVCONTAINER_DIR="/project/.devcontainer"
|
|
10
|
+
HOME_DIR="/home/$(whoami)"
|
|
11
|
+
|
|
12
|
+
# Create directories if they don't exist
|
|
13
|
+
mkdir -p "${DEVCONTAINER_DIR}/.claude"
|
|
14
|
+
mkdir -p "${DEVCONTAINER_DIR}/qmd-config"
|
|
15
|
+
mkdir -p "${DEVCONTAINER_DIR}/qmd-cache"
|
|
16
|
+
|
|
17
|
+
# Create files if they don't exist
|
|
18
|
+
if [ ! -f "${DEVCONTAINER_DIR}/.claude.json" ]; then
|
|
19
|
+
echo "{}" > "${DEVCONTAINER_DIR}/.claude.json"
|
|
20
|
+
fi
|
|
21
|
+
if [ ! -f "${DEVCONTAINER_DIR}/.claude.json.backup" ]; then
|
|
22
|
+
echo "{}" > "${DEVCONTAINER_DIR}/.claude.json.backup"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Ensure proper ownership
|
|
26
|
+
chown -R $(whoami):$(whoami) "${DEVCONTAINER_DIR}/.claude"
|
|
27
|
+
chown -R $(whoami):$(whoami) "${DEVCONTAINER_DIR}/qmd-config"
|
|
28
|
+
chown -R $(whoami):$(whoami) "${DEVCONTAINER_DIR}/qmd-cache"
|
|
29
|
+
chown $(whoami):$(whoami) "${DEVCONTAINER_DIR}/.claude.json"
|
|
30
|
+
chown $(whoami):$(whoami) "${DEVCONTAINER_DIR}/.claude.json.backup"
|
|
31
|
+
|
|
32
|
+
# Create symlinks if they don't exist
|
|
33
|
+
if [ ! -L "${HOME_DIR}/.claude" ]; then
|
|
34
|
+
ln -sf "${DEVCONTAINER_DIR}/.claude" "${HOME_DIR}/"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [ ! -L "${HOME_DIR}/.config/qmd" ]; then
|
|
38
|
+
ln -sf "${DEVCONTAINER_DIR}/qmd-config" "${HOME_DIR}/.config/qmd"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if [ ! -L "${HOME_DIR}/.cache/qmd" ]; then
|
|
42
|
+
ln -sf "${DEVCONTAINER_DIR}/qmd-cache" "${HOME_DIR}/.cache/qmd"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ ! -L "${HOME_DIR}/.claude.json" ]; then
|
|
46
|
+
ln -sf "${DEVCONTAINER_DIR}/.claude.json" "${HOME_DIR}/.claude.json"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ ! -L "${HOME_DIR}/.claude.json.backup" ]; then
|
|
50
|
+
ln -sf "${DEVCONTAINER_DIR}/.claude.json.backup" "${HOME_DIR}/.claude.json.backup"
|
|
51
|
+
fi
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# devcontainer
|
|
2
|
+
!.devcontainer/.claude
|
|
3
|
+
.devcontainer/.claude/*
|
|
4
|
+
.devcontainer/.claude.json
|
|
5
|
+
.devcontainer/.claude.json.backup
|
|
6
|
+
.devcontainer/qmd-cache/
|
|
7
|
+
.devcontainer/data
|
|
8
|
+
.devcontainer/uv
|
|
9
|
+
.devcontainer/local
|
|
10
|
+
|
|
11
|
+
# Python
|
|
12
|
+
__pycache__/
|
|
13
|
+
*.py[cod]
|
|
14
|
+
*.egg-info/
|
|
15
|
+
.venv/
|
|
16
|
+
|
|
17
|
+
# claude
|
|
18
|
+
.claude/settings.local.json
|
|
19
|
+
CLAUDE.local.md
|
|
20
|
+
|
|
21
|
+
# Test artifacts
|
|
22
|
+
snapshot_report.html
|
|
23
|
+
|
|
24
|
+
# Environment
|
|
25
|
+
.env
|
|
26
|
+
.env.local
|
|
27
|
+
|
|
28
|
+
# Downloaded library docs
|
|
29
|
+
docs/libs/
|
|
30
|
+
|
|
31
|
+
# --- gitignore end ---
|
|
32
|
+
|
|
33
|
+
dist/
|
|
34
|
+
.devcontainer/qmd-config/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
# end_of_line = lf
|
|
5
|
+
|
|
6
|
+
[*.py]
|
|
7
|
+
indent_style = space
|
|
8
|
+
indent_size = 4
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
charset = utf-8
|
|
11
|
+
|
|
12
|
+
[*.{yml,yaml}]
|
|
13
|
+
indent_style = space
|
|
14
|
+
indent_size = 2
|
|
15
|
+
trim_trailing_whitespace = true
|
|
16
|
+
insert_final_newline = true
|
|
17
|
+
charset = utf-8
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
# Publish on any tag starting with a `v`, e.g. v1.2.3
|
|
7
|
+
- v*
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
pypi:
|
|
11
|
+
name: Publish to PyPI
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
environment:
|
|
14
|
+
name: release
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: astral-sh/setup-uv@v3
|
|
20
|
+
- run: uv build
|
|
21
|
+
- run: uv publish --trusted-publishing always
|
|
22
|
+
|
|
23
|
+
github-release:
|
|
24
|
+
name: Create GitHub Release
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- name: Extract changelog for this version
|
|
31
|
+
id: changelog
|
|
32
|
+
run: |
|
|
33
|
+
version="${GITHUB_REF_NAME#v}"
|
|
34
|
+
# Extract the section for this version from CHANGELOG.md
|
|
35
|
+
body=$(awk -v ver="$version" '
|
|
36
|
+
/^## \[/ {
|
|
37
|
+
if (found) exit
|
|
38
|
+
if (index($0, "[" ver "]")) found=1
|
|
39
|
+
next
|
|
40
|
+
}
|
|
41
|
+
found { print }
|
|
42
|
+
' CHANGELOG.md)
|
|
43
|
+
# Write to file to preserve newlines
|
|
44
|
+
echo "$body" > release_body.md
|
|
45
|
+
- name: Create GitHub Release
|
|
46
|
+
uses: softprops/action-gh-release@v2
|
|
47
|
+
with:
|
|
48
|
+
body_path: release_body.md
|
|
49
|
+
generate_release_notes: false
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# devcontainer
|
|
2
|
+
!.devcontainer/.claude
|
|
3
|
+
.devcontainer/.claude/*
|
|
4
|
+
.devcontainer/.claude.json
|
|
5
|
+
.devcontainer/.claude.json.backup
|
|
6
|
+
.devcontainer/qmd-cache/
|
|
7
|
+
.devcontainer/data
|
|
8
|
+
.devcontainer/uv
|
|
9
|
+
.devcontainer/local
|
|
10
|
+
|
|
11
|
+
# Python
|
|
12
|
+
__pycache__/
|
|
13
|
+
*.py[cod]
|
|
14
|
+
*.egg-info/
|
|
15
|
+
.venv/
|
|
16
|
+
|
|
17
|
+
# claude
|
|
18
|
+
.claude/
|
|
19
|
+
CLAUDE.local.md
|
|
20
|
+
|
|
21
|
+
# Test artifacts
|
|
22
|
+
snapshot_report.html
|
|
23
|
+
|
|
24
|
+
# Environment
|
|
25
|
+
.env
|
|
26
|
+
.env.local
|
|
27
|
+
|
|
28
|
+
# Downloaded library docs
|
|
29
|
+
docs/libs/
|
|
@@ -6,8 +6,10 @@ repos:
|
|
|
6
6
|
entry: ruff check --force-exclude --fix
|
|
7
7
|
language: python
|
|
8
8
|
types_or: [python, pyi, jupyter]
|
|
9
|
+
additional_dependencies: [ruff]
|
|
9
10
|
- id: ruff-format
|
|
10
11
|
name: ruff format
|
|
11
12
|
entry: ruff format --force-exclude
|
|
12
13
|
language: python
|
|
13
14
|
types_or: [python, pyi, jupyter]
|
|
15
|
+
additional_dependencies: [ruff]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.1] - 2026-03-18
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Wheel build only included `.scm` grammar files, excluding all Python source — caused `ModuleNotFoundError` when installed via `pip install` or `uv tool install`
|
|
15
|
+
|
|
16
|
+
## [0.1.0] - 2026-03-18
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Editor**: multiple cursors with Ctrl+Alt+Up/Down, add next occurrence (Ctrl+D), select all occurrences (Ctrl+Shift+L); multi-cursor movement, selection, typing, and editing all work simultaneously; move line up/down (Alt+Up/Down), scroll viewport (Ctrl+Up/Down), select all (Ctrl+A), double/triple click word/line selection, Ctrl+C/X copies/cuts current line when no selection, Tab/Shift+Tab indent/dedent, Ctrl+Shift+Z redo
|
|
21
|
+
- **Find & Replace**: inline find/replace bar (Ctrl+F/Ctrl+H) with regex, case-sensitivity, and Select All matches for multi-cursor editing; workspace-wide search (Ctrl+Shift+F) and Replace All with gitignore, file include/exclude filters, case-sensitivity toggle, and background search with loading indicator
|
|
22
|
+
- **Split view**: unlimited nested horizontal/vertical splits via recursive tree structure; split in any direction (Ctrl+\\, command palette); close split (Ctrl+Shift+\\); drag-and-drop tabs between splits with 4-direction edge zones and visual drop hints; drag resize handles; toggle split orientation; directional tab move commands; move tab to other split (Ctrl+Alt+\\); live text sync between split editors viewing the same file; focus cycling with F6/Shift+F6
|
|
23
|
+
- **Explorer**: create file/directory (Ctrl+N/Ctrl+D in sidebar), delete file/folder (Delete key); toggle hidden files, dim gitignored files, dim hidden files, git status highlighting (modified in yellow, untracked in green with folder inheritance); auto-refresh on workspace file changes and git status changes; cursor sync with active editor tab; responsive emoji icons that collapse at narrow widths
|
|
24
|
+
- **File handling**: new file (Ctrl+N), Save As, reload file from disk; expanded encoding auto-detection (40+ encodings including CJK via charset-normalizer); binary file detection; EditorConfig support with auto-reload on `.editorconfig` changes; `trim_trailing_whitespace` and `insert_final_newline` applied at save time; configurable line endings; free-form indentation size input; external file change detection with auto-reload or overwrite confirmation
|
|
25
|
+
- **Tabs & navigation**: command palette (Ctrl+Shift+P) for quick access to all commands; tab reorder by drag, cross-split tab drag, Goto Line (Ctrl+G), copy relative/absolute path, close all (Ctrl+Shift+W), save all (Ctrl+Shift+S), toggle sidebar (Ctrl+B), sidebar drag resize, resize sidebar/split via command palette
|
|
26
|
+
- **Markdown**: live preview in tab (Ctrl+Shift+M) with debounced auto-updates, GFM support, keyboard scrolling; preview closes with source editor
|
|
27
|
+
- **Themes**: UI theme selection from 20 built-in themes (nord, gruvbox, dracula, etc.); syntax highlighting theme selection (monokai, dracula, github_light, vscode_dark, css)
|
|
28
|
+
- **Keyboard shortcuts**: view and customize all key bindings (F1), shortcut hints in command palette, custom bindings saved to keybindings.toml
|
|
29
|
+
- **Configuration**: user-level and project-level settings persistence (TOML) with project taking priority; open settings commands; save-level selector (User/Project) in theme and default settings dialogs; `sidebar_width`, `path_display_mode`, `warn_line_ending`, word wrap toggle and default settings; `--workspace` / `-w` CLI option for overriding sidebar root directory
|
|
30
|
+
- **Language support**: syntax highlighting for 10 additional languages (TypeScript, TSX, C, C++, Ruby, Kotlin, Lua, PHP, Dockerfile, Makefile) via tree-sitter-language-pack; extended file type detection for dotfiles and additional extensions
|
|
31
|
+
- **Footer**: clickable file path copies to clipboard; path display mode toggle (absolute/relative); cursor position with multi-cursor count; clickable language, encoding, line ending, and indentation indicators; dynamic column sizing
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Default word wrap changed to enabled
|
|
36
|
+
- Footer path truncation indicator visually distinct from actual path characters
|
|
37
|
+
|
|
38
|
+
## [0.0.2] - 2025-01-07
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Add basic text editing features
|
|
43
|
+
|
|
44
|
+
[unreleased]: https://github.com/rishubil/textual-code/compare/v0.1.1...HEAD
|
|
45
|
+
[0.1.1]: https://github.com/rishubil/textual-code/compare/v0.1.0...v0.1.1
|
|
46
|
+
[0.1.0]: https://github.com/rishubil/textual-code/compare/v0.0.2...v0.1.0
|
|
47
|
+
[0.0.2]: https://github.com/rishubil/textual-code/releases/tag/v0.0.2
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
**CRITICAL RULES:**
|
|
4
|
+
- Put the truth and the correct answer above all else. Feel free to criticize user's opinion, and do not use false empathy with the user. Keep a dry and realistic perspective.
|
|
5
|
+
- Use qmd to check documentation on every task to maintain consistency
|
|
6
|
+
- **Always run Python with `uv`**: never call `python` or `pip` directly; always use `uv run python`, `uv run pytest`, `uv run ruff`, etc.
|
|
7
|
+
- **Avoid `$()` in Bash tool calls**: `$()` command substitution triggers extra user confirmation in Claude Code. Split into separate Bash tool calls instead:
|
|
8
|
+
```
|
|
9
|
+
# BAD — single Bash call with nested $() requires extra confirmation
|
|
10
|
+
uv run pytest tests/ -n $(( $(nproc) * 2 )) -m "not serial"
|
|
11
|
+
|
|
12
|
+
# GOOD — two separate Bash tool calls
|
|
13
|
+
Call 1: nproc → returns e.g. "4"
|
|
14
|
+
Call 2: uv run pytest tests/ -n 8 -m "not serial"
|
|
15
|
+
```
|
|
16
|
+
Read the output of the first call and substitute the value directly into the second call.
|
|
17
|
+
- Use WebFetch proactively. Always check the latest development docs and search for anything unclear.
|
|
18
|
+
- All code comments, docstrings, and documentation (including files in `docs/`) must be written in **English**.
|
|
19
|
+
|
|
20
|
+
## Test Strategy: Red-Green TDD
|
|
21
|
+
|
|
22
|
+
> See `docs/testing-guide.md` for test patterns, best practices, and gotchas (`make_app(light=True)`, `pilot.pause()` rules, snapshot conventions, etc.)
|
|
23
|
+
|
|
24
|
+
**Before starting work, check and run existing tests:**
|
|
25
|
+
|
|
26
|
+
1. **Find test files**: use Glob/Grep to find test files related to the code you are modifying
|
|
27
|
+
2. **Run existing tests**: run tests before starting work to understand the current state (pass/fail)
|
|
28
|
+
3. **Establish a baseline**: know which tests pass before your changes so you can detect regressions
|
|
29
|
+
|
|
30
|
+
**Apply Red-Green TDD to modification tasks:**
|
|
31
|
+
|
|
32
|
+
- **Red**: first write or identify a test that verifies the behaviour to be changed (failing state)
|
|
33
|
+
- **Green**: implement the minimum code needed to make the test pass
|
|
34
|
+
- **Verify**: confirm that all pre-existing tests still pass
|
|
35
|
+
|
|
36
|
+
**When modifying code with no tests:**
|
|
37
|
+
- Add tests before modifying if possible
|
|
38
|
+
- If adding tests is out of scope, state it explicitly: "This change has no tests"
|
|
39
|
+
|
|
40
|
+
**When adding new UI (modal / widget / screen):**
|
|
41
|
+
- A snapshot test is **mandatory**. Add it to `tests/test_snapshots.py` before the implementation is merged.
|
|
42
|
+
- Use `_open_editor_modal` helper for editor-triggered modals; use `_open_app_modal` for app-level modals.
|
|
43
|
+
- Run `uv run pytest tests/test_snapshots.py --snapshot-update` after adding the test to generate the SVG.
|
|
44
|
+
|
|
45
|
+
## Textual Official Documentation
|
|
46
|
+
|
|
47
|
+
When Textual framework behaviour (API, Widget, Screen, Worker, reactive, etc.) is uncertain, **always search the local docs before implementing**.
|
|
48
|
+
|
|
49
|
+
- **Local docs**: `docs/libs/textual/` (MkDocs format, mirrored from textual.textualize.io)
|
|
50
|
+
- Key topics: App · ModalScreen · push_screen · dismiss · Message · on_* · reactive · watch_* · Worker · @work · BINDINGS · Binding · action_* · CommandPalette · Provider · TCSS · TabbedContent · TabPane · DirectoryTree · TextArea
|
|
51
|
+
|
|
52
|
+
**No guessing**: if behaviour is unclear, search the local docs first.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
See @README.md for project overview
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: textual-code
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Code editor for who don't know how to use vi
|
|
5
|
+
Project-URL: Repository, https://github.com/rishubil/textual-code.git
|
|
6
|
+
Project-URL: Changelog, https://github.com/rishubil/textual-code/blob/master/CHANGELOG.md
|
|
7
|
+
Author-email: Nesswit <rishubil@gmail.com>
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Text Editors
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: charset-normalizer>=3.0.0
|
|
20
|
+
Requires-Dist: pathspec>=1.0.4
|
|
21
|
+
Requires-Dist: textual[syntax]>=1.0.0
|
|
22
|
+
Requires-Dist: tree-sitter-language-pack>=0.13.0
|
|
23
|
+
Requires-Dist: typer>=0.15.1
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Textual Code
|
|
27
|
+
|
|
28
|
+
Code editor for who don't know how to use vi
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
> [!WARNING]
|
|
33
|
+
> This project is in the early stages of development.
|
|
34
|
+
> It is not ready for use yet.
|
|
35
|
+
|
|
36
|
+
## What is Textual Code?
|
|
37
|
+
|
|
38
|
+
Textual Code is a TUI-based code editor that feels familiar right from the start.
|
|
39
|
+
|
|
40
|
+
You’ve probably had to SSH into a server at some point just to tweak a few lines of code.
|
|
41
|
+
However, vi or Emacs can be overkill for quick fixes, requiring you to remember a whole host of commands for even the simplest changes.
|
|
42
|
+
Furthermore, nano doesn’t always provide enough features for comfortable coding, and setting up a GUI editor on a remote server can be a real hassle.
|
|
43
|
+
|
|
44
|
+
That’s why Textual Code was created.
|
|
45
|
+
You likely use a GUI editor like VS Code or Sublime Text in your day-to-day work, and Textual Code offers a similar experience with no learning curve.
|
|
46
|
+
It behaves much like any other code editor you’re used to.
|
|
47
|
+
|
|
48
|
+
We’re not asking you to switch to Textual Code as your main editor.
|
|
49
|
+
Just remember it’s there when you need to jump onto a server and make a few quick edits.
|
|
50
|
+
It’s that simple.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
> [!WARNING]
|
|
55
|
+
> This project is in the early stages of development.
|
|
56
|
+
> the features listed below are not yet implemented or are only partially implemented.
|
|
57
|
+
|
|
58
|
+
- Commonly used shortcuts, such as `Ctrl+S` to save and `Ctrl+F` to search
|
|
59
|
+
- Command palette for quick access to all features, and no need to remember shortcuts
|
|
60
|
+
- Multiple cursors
|
|
61
|
+
- Mouse support
|
|
62
|
+
- Find and replace from workspace
|
|
63
|
+
- Explore files in the sidebar
|
|
64
|
+
- Open files to tabs
|
|
65
|
+
- Syntax highlighting
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install textual-code
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
To open the textual code, run the following command in your workspace:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
textual-code
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Development
|
|
82
|
+
|
|
83
|
+
(You need to use devcontainer to run the code)
|
|
84
|
+
|
|
85
|
+
To run the development version directly:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv run textual-code
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
To run with the Textual dev console (shows logs and events), open two terminals:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Terminal 1: start the console
|
|
95
|
+
uv run textual console
|
|
96
|
+
|
|
97
|
+
# Terminal 2: run the app in dev mode
|
|
98
|
+
uv run textual run --dev textual_code:main
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Running Tests
|
|
102
|
+
|
|
103
|
+
See [docs/testing-guide.md](docs/testing-guide.md) for patterns, best practices, and gotchas.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Unit/integration tests — parallel (~2.5 min)
|
|
107
|
+
uv run pytest tests/ -n $(( $(nproc) * 2 )) -m "not serial"
|
|
108
|
+
|
|
109
|
+
# Snapshot tests — must run serially
|
|
110
|
+
uv run pytest tests/ -m serial
|
|
111
|
+
|
|
112
|
+
# Update snapshots after UI changes
|
|
113
|
+
uv run pytest tests/test_snapshots.py --snapshot-update
|
|
114
|
+
|
|
115
|
+
# Single file
|
|
116
|
+
uv run pytest tests/test_code_editor.py
|
|
117
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Textual Code
|
|
2
|
+
|
|
3
|
+
Code editor for who don't know how to use vi
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> This project is in the early stages of development.
|
|
9
|
+
> It is not ready for use yet.
|
|
10
|
+
|
|
11
|
+
## What is Textual Code?
|
|
12
|
+
|
|
13
|
+
Textual Code is a TUI-based code editor that feels familiar right from the start.
|
|
14
|
+
|
|
15
|
+
You’ve probably had to SSH into a server at some point just to tweak a few lines of code.
|
|
16
|
+
However, vi or Emacs can be overkill for quick fixes, requiring you to remember a whole host of commands for even the simplest changes.
|
|
17
|
+
Furthermore, nano doesn’t always provide enough features for comfortable coding, and setting up a GUI editor on a remote server can be a real hassle.
|
|
18
|
+
|
|
19
|
+
That’s why Textual Code was created.
|
|
20
|
+
You likely use a GUI editor like VS Code or Sublime Text in your day-to-day work, and Textual Code offers a similar experience with no learning curve.
|
|
21
|
+
It behaves much like any other code editor you’re used to.
|
|
22
|
+
|
|
23
|
+
We’re not asking you to switch to Textual Code as your main editor.
|
|
24
|
+
Just remember it’s there when you need to jump onto a server and make a few quick edits.
|
|
25
|
+
It’s that simple.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
> [!WARNING]
|
|
30
|
+
> This project is in the early stages of development.
|
|
31
|
+
> the features listed below are not yet implemented or are only partially implemented.
|
|
32
|
+
|
|
33
|
+
- Commonly used shortcuts, such as `Ctrl+S` to save and `Ctrl+F` to search
|
|
34
|
+
- Command palette for quick access to all features, and no need to remember shortcuts
|
|
35
|
+
- Multiple cursors
|
|
36
|
+
- Mouse support
|
|
37
|
+
- Find and replace from workspace
|
|
38
|
+
- Explore files in the sidebar
|
|
39
|
+
- Open files to tabs
|
|
40
|
+
- Syntax highlighting
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install textual-code
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
To open the textual code, run the following command in your workspace:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
textual-code
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
(You need to use devcontainer to run the code)
|
|
59
|
+
|
|
60
|
+
To run the development version directly:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv run textual-code
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
To run with the Textual dev console (shows logs and events), open two terminals:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Terminal 1: start the console
|
|
70
|
+
uv run textual console
|
|
71
|
+
|
|
72
|
+
# Terminal 2: run the app in dev mode
|
|
73
|
+
uv run textual run --dev textual_code:main
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Running Tests
|
|
77
|
+
|
|
78
|
+
See [docs/testing-guide.md](docs/testing-guide.md) for patterns, best practices, and gotchas.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Unit/integration tests — parallel (~2.5 min)
|
|
82
|
+
uv run pytest tests/ -n $(( $(nproc) * 2 )) -m "not serial"
|
|
83
|
+
|
|
84
|
+
# Snapshot tests — must run serially
|
|
85
|
+
uv run pytest tests/ -m serial
|
|
86
|
+
|
|
87
|
+
# Update snapshots after UI changes
|
|
88
|
+
uv run pytest tests/test_snapshots.py --snapshot-update
|
|
89
|
+
|
|
90
|
+
# Single file
|
|
91
|
+
uv run pytest tests/test_code_editor.py
|
|
92
|
+
```
|