Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/publish-apps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ runs:
run: pip install boto3
- name: 'Upload files'
shell: bash
run: python Scripts/CDN/upload-app-files.py cdn_files ${{ inputs.sdk_version }} ${{ env.CDN_ID }} ${{ env.CDN_TOKEN_NAME }} ${{ env.CDN_TOKEN_VALUE }}
run: python Scripts/upload-app-files.py cdn_files ${{ inputs.sdk_version }} ${{ env.CDN_ID }} ${{ env.CDN_TOKEN_NAME }} ${{ env.CDN_TOKEN_VALUE }}
2 changes: 1 addition & 1 deletion .github/actions/release-apps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ runs:
id: release
shell: bash
run: |
python release.py cdn_files/
python Scripts/release.py cdn_files/
echo "sdk_version=$(cat sdk_version.txt)" >> "$GITHUB_OUTPUT"
- name: 'Upload Artifact'
uses: actions/upload-artifact@v4
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ sdkconfig.old
.tactility/

dependencies.lock

__pycache__
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,18 @@ void* llist_pop(llist_t** elm);

/* region Memory and strings */

/* Allocations from the x*() functions are tracked, see bb_free_all() */
void* xmalloc(size_t size);
void* xzalloc(size_t size);
void* xrealloc(void* old, size_t size);
char* xstrdup(const char* s);
char* xstrndup(const char* s, int n);
char* xasprintf(const char* format, ...) __attribute__((format(printf, 1, 2)));
/* vi frees x*() allocations with plain free() */
void bb_free(void* ptr);
#define free bb_free
/* Frees every x*() allocation that is still live */
void bb_free_all(void);

char* skip_whitespace(const char* s);
char* skip_non_whitespace(const char* s);
Expand Down
87 changes: 73 additions & 14 deletions Apps/Vi/main/Source/libbb.c → Apps/BusyBoxVi/main/Source/libbb.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*/
#include "libbb.h"

/* This file implements bb_free() itself, so free() means libc's own below */
#undef free

struct globals* ptr_to_globals;
const char* applet_name = "vi";

Expand All @@ -27,20 +30,57 @@ void* llist_pop(llist_t** head) {
}
void* data = temp->data;
*head = temp->link;
free(temp);
bb_free(temp);
return data;
}

/* endregion */

/* region Memory and strings */

/*
* Every block handed out below is tracked, so bb_free_all() can release what vi itself never frees
* (it relies on process exit, which an app instance doesn't have).
*/
typedef union AllocHeader {
struct {
union AllocHeader* prev;
union AllocHeader* next;
} links;
max_align_t alignment;
} AllocHeader;

static AllocHeader* allocations = NULL;

static void* track(AllocHeader* header) {
header->links.prev = NULL;
header->links.next = allocations;
if (allocations != NULL) {
allocations->links.prev = header;
}
allocations = header;
return header + 1;
}

static AllocHeader* untrack(void* ptr) {
AllocHeader* header = (AllocHeader*)ptr - 1;
if (header->links.prev != NULL) {
header->links.prev->links.next = header->links.next;
} else {
allocations = header->links.next;
}
if (header->links.next != NULL) {
header->links.next->links.prev = header->links.prev;
}
return header;
}

void* xmalloc(size_t size) {
void* ptr = malloc(size);
if (ptr == NULL && size != 0) {
AllocHeader* header = malloc(sizeof(AllocHeader) + size);
if (header == NULL) {
bb_simple_error_msg_and_die("out of memory");
}
return ptr;
return track(header);
}

void* xzalloc(size_t size) {
Expand All @@ -50,18 +90,34 @@ void* xzalloc(size_t size) {
}

void* xrealloc(void* old, size_t size) {
void* ptr = realloc(old, size);
if (ptr == NULL && size != 0) {
if (old == NULL) {
return xmalloc(size);
}
AllocHeader* header = realloc(untrack(old), sizeof(AllocHeader) + size);
if (header == NULL) {
bb_simple_error_msg_and_die("out of memory");
}
return ptr;
return track(header);
}

char* xstrdup(const char* s) {
char* t = strdup(s);
if (t == NULL) {
bb_simple_error_msg_and_die("out of memory");
void bb_free(void* ptr) {
if (ptr != NULL) {
free(untrack(ptr));
}
}

void bb_free_all(void) {
while (allocations != NULL) {
AllocHeader* next = allocations->links.next;
free(allocations);
allocations = next;
}
}

char* xstrdup(const char* s) {
size_t size = strlen(s) + 1;
char* t = xmalloc(size);
memcpy(t, s, size);
return t;
}

Expand Down Expand Up @@ -257,7 +313,7 @@ void* xmalloc_open_read_close(const char* filename, size_t* maxsz_p) {
}
ssize_t n = safe_read(fd, buf + size, capacity - size - 1);
if (n < 0) {
free(buf);
bb_free(buf);
close(fd);
return NULL;
}
Expand All @@ -282,14 +338,17 @@ void bb_putchar(int ch) {

/* region Errors */

/* exit() would terminate the whole device, so dying unwinds to main() instead */
jmp_buf bb_die_jmp;

void bb_show_usage(void) {
fputs("Usage: vi [-c CMD] [-R] [-H] [FILE]...\n", stderr);
exit(EXIT_FAILURE);
longjmp(bb_die_jmp, 1);
}

void bb_simple_error_msg_and_die(const char* s) {
fprintf(stderr, "%s: %s\n", applet_name, s);
exit(EXIT_FAILURE);
longjmp(bb_die_jmp, 1);
}
Comment thread
KenVanHoeylandt marked this conversation as resolved.

/* endregion */
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Expand Down
23 changes: 23 additions & 0 deletions Apps/BusyBoxVi/main/Source/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed under GPLv2, see file LICENSE in this app's directory.
*/
#include <setjmp.h>
#include <stdlib.h>

int vi_main(int argc, char** argv);
void bb_free_all(void);
void vi_cleanup(void);
extern jmp_buf bb_die_jmp;

int main(int argc, char* argv[]) {
int result;
if (setjmp(bb_die_jmp) == 0) {
result = vi_main(argc, argv);
} else {
vi_cleanup();
Comment thread
KenVanHoeylandt marked this conversation as resolved.
result = EXIT_FAILURE;
}
/* vi leaves its buffers to process exit, which an app instance doesn't have */
bb_free_all();
return result;
}
File renamed without changes.
21 changes: 21 additions & 0 deletions Apps/Vi/main/Source/vi.c → Apps/BusyBoxVi/main/Source/vi.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,16 +626,35 @@ static int mysleep(int hund)
}

//----- Set terminal attributes --------------------------------
static bool termios_saved;

static void rawmode(void)
{
// no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals
set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL);
termios_saved = true;
}

static void cookmode(void)
{
if (!termios_saved)
return;
fflush_all();
tcsetattr_stdin_TCSANOW(&term_orig);
termios_saved = false;
}

// Set while the alternate screen buffer is in use, so vi_cleanup() can leave it
static smallint alt_screen_active;

void vi_cleanup(void)
{
if (alt_screen_active) {
// "Use normal screen buffer, restore cursor"
write1(ESC"[?1049l");
alt_screen_active = 0;
}
cookmode();
}

//----- Terminal Drawing ---------------------------------------
Expand Down Expand Up @@ -5037,6 +5056,7 @@ int vi_main(int argc, char **argv)
#endif
// "Save cursor, use alternate screen buffer, clear screen"
write1(ESC"[?1049h");
alt_screen_active = 1;
// This is the main file handling loop
optind = 0;
while (1) {
Expand All @@ -5048,6 +5068,7 @@ int vi_main(int argc, char **argv)
}
// "Use normal screen buffer, restore cursor"
write1(ESC"[?1049l");
alt_screen_active = 0;

return 0;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
manifest.version=0.3
target.sdk=0.8.0-dev
target.platforms=esp32,esp32s3,esp32c6,esp32p4,posix-x86_64
id=tactility.vi
id=tactility.busyboxvi
version.name=0.1.0
version.code=1
name=Vi
description=BusyBox vi text editor
app.0.id=tactility.vi
app.0.name=Vi
app.0.id=tactility.busyboxvi
app.0.name=BusyBox vi
app.0.binary=vi
app.0.hidden=true
app.0.headless=true
app.0.stack.depth=8192
app.0.stack.depth=4096
13 changes: 13 additions & 0 deletions Apps/Neatvi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# tactility-cmakelists-version: 1
cmake_minimum_required(VERSION 3.20)

if (NOT DEFINED ENV{TACTILITY_SDK_PATH})
message(FATAL_ERROR "TACTILITY_SDK_PATH environment variable is not set")
endif()

get_filename_component(TACTILITY_SDK_PATH "$ENV{TACTILITY_SDK_PATH}" ABSOLUTE)
include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake")

tactility_project_pre(vi)
project(vi)
tactility_project_post(vi)
15 changes: 15 additions & 0 deletions Apps/Neatvi/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

Copyright (C) 2015-2026 Ali Gholami Rudi <ali at rudi dot ir>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

33 changes: 33 additions & 0 deletions Apps/Neatvi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Vi

The [neatvi](https://github.com/aligrudi/neatvi) text editor for the Tactility terminal.

## Usage

Run it from the Terminal app:

```
vi [-v] [-e] [FILE]...
```

- `-v`: start in vi mode (default)
- `-e`: start in ex mode

## Features

- vi and ex commands, including `:w`, `:q`, `:wq`, `:e`, `:r`, `:s/old/new/`
- Regular expression search and substitution
- Multiple buffers, registers, marks, undo/redo
- Syntax highlighting (see `conf.c`)

Not supported: `:!` shell commands, filters and pipes, and LSP support (Tactility can't start other processes).
The terminal has no Home/End/PgUp/PgDn keys: use `0`, `$`, `Ctrl+B` and `Ctrl+F`.

## Source

`main/Source` holds neatvi (upstream commit `26e9cad`), unmodified, without `cmd.c`, `lsp.c`, `json.c` and `stag.c`.
`main/Source/tactility.c` replaces `cmd.c` and `lsp.c`, which need `fork()`.

## License

neatvi is licensed under the ISC license, see [LICENSE](LICENSE).
12 changes: 12 additions & 0 deletions Apps/Neatvi/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include("$ENV{TACTILITY_SDK_PATH}/TactilitySDK.cmake")

file(GLOB_RECURSE SOURCE_FILES Source/*.c)
tactility_component_register(SRCS ${SOURCE_FILES})

# neatvi code style (third-party, kept unmodified)
set(NEATVI_COMPILE_OPTIONS -Wno-missing-field-initializers -Wno-char-subscripts -Wno-implicit-fallthrough -Wno-format-truncation)
if (DEFINED COMPONENT_LIB)
target_compile_options(${COMPONENT_LIB} PRIVATE ${NEATVI_COMPILE_OPTIONS})
else ()
target_compile_options(${PROJECT_NAME} PRIVATE ${NEATVI_COMPILE_OPTIONS})
endif ()
Loading
Loading