Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm Error : JavaScript execution returned a result of an unsupported type #779

Open
woncheol-kim opened this issue May 18, 2024 · 6 comments

Comments

@woncheol-kim
Copy link

I have tried to compile various TUI file managers into WebAssembly, but all my attempts have failed. Subsequently, I decided to develop a new file manager myself, with assistance from ChatGPT, as I am not actually a programmer.

My development is still in its very early stages. I am frustrated to learn that the termios library is not compatible with WebAssembly. Additionally, I am wondering why my compiled file manager is occasionally terminated with the following error:

wasm Error: JavaScript execution returned a result of an unsupported type

Please find below the source code of my development so far:

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

#define MAX_PATH 1024
#define MAX_ENTRIES 1024

struct entry {
char name[MAX_PATH];
int is_dir;
int selected;
};

struct entry entries[MAX_ENTRIES];
int num_entries = 0;
int current_pos = 0;
int selected_count = 0;

void get_entries(char *path) {
DIR *dir = opendir(path);
struct dirent *entry;
num_entries = 0;

if (dir == NULL) {
    perror("opendir");
    return;
}

while ((entry = readdir(dir)) != NULL) {
    if (entry->d_name[0] != '.') {
        strcpy(entries[num_entries].name, entry->d_name);
        entries[num_entries].is_dir = entry->d_type == DT_DIR;
        entries[num_entries].selected = 0;
        num_entries++;
    }
}

closedir(dir);

}

void draw() {
printf("\033[H\033[J"); // Clear screen
printf("Current directory: %s\n\n", getcwd(NULL, 0));

for (int i = 0; i < num_entries; i++) {
    if (i == current_pos) {
        printf("\033[7m"); // Inverse video
    }
    if (entries[i].selected) {
        printf("* "); // Represent selected files/directories with *
    } else {
        printf("  ");
    }
    printf("%c %s\n", entries[i].is_dir ? '/' : ' ', entries[i].name);
    if (i == current_pos) {
        printf("\033[0m"); // Reset attributes
    }
}

}

void select_all() {
for (int i = 0; i < num_entries; i++) {
entries[i].selected = 1;
}
selected_count = num_entries;
}

void invert_selection() {
for (int i = 0; i < num_entries; i++) {
entries[i].selected = !entries[i].selected;
}
selected_count = num_entries - selected_count;
}

void clear_selections() {
for (int i = 0; i < num_entries; i++) {
entries[i].selected = 0;
}
selected_count = 0;
}

int main() {
char cwd[MAX_PATH];
getcwd(cwd, sizeof(cwd));
get_entries(cwd);
draw();

while (1) {
    char c = getchar();

    switch (c) {
        case 'k':
            current_pos = (current_pos - 1 + num_entries) % num_entries;
            break;
        case 'j':
            current_pos = (current_pos + 1) % num_entries;
            break;
        case 'h':
            chdir("..");
            getcwd(cwd, sizeof(cwd));
            get_entries(cwd);
            break;
        case 'l':
            if (entries[current_pos].is_dir) {
                chdir(entries[current_pos].name);
                getcwd(cwd, sizeof(cwd));
                get_entries(cwd);
                current_pos = 0;
            }
            break;
        case 'g':
            current_pos = 0;
            break;
        case 'G':
            current_pos = num_entries - 1;
            break;
        case 'q':
            exit(0);
        case ' ':
            entries[current_pos].selected = !entries[current_pos].selected;
            selected_count += entries[current_pos].selected ? 1 : -1;
            // Set the item one below the current hovering item as the new hovering item
            current_pos = (current_pos + 1) % num_entries;
            break;
        case 'a':
            select_all();
            break;
        case 'A':
            invert_selection();
            break;
        case 'x':
            if (selected_count == 0) {
                char path[MAX_PATH];
                snprintf(path, sizeof(path), "%s/%s", cwd, entries[current_pos].name);
                if (entries[current_pos].is_dir) {
                    rmdir(path);
                } else {
                    remove(path);
                }
            } else {
                for (int i = 0; i < num_entries; i++) {
                    if (entries[i].selected) {
                        char path[MAX_PATH];
                        snprintf(path, sizeof(path), "%s/%s", cwd, entries[i].name);
                        if (entries[i].is_dir) {
                            rmdir(path);
                        } else {
                            remove(path);
                        }
                    }
                }
            }
            getcwd(cwd, sizeof(cwd));
            get_entries(cwd);
            current_pos = 0;
            selected_count = 0;
            break;
        case 'v':
            for (int i = 0; i < num_entries; i++) {
                if (entries[i].selected) {
                    char src_path[MAX_PATH];
                    char dst_path[MAX_PATH];
                    snprintf(src_path, sizeof(src_path), "%s/%s", cwd, entries[i].name);
                    snprintf(dst_path, sizeof(dst_path), "%s/%s", cwd, entries[i].name);
                    rename(src_path, dst_path);
                }
            }
            getcwd(cwd, sizeof(cwd));
            get_entries(cwd);
            current_pos = 0;
            selected_count = 0;
            break;
        case 'm':
            clear_selections();
            break;
    }

    draw();
}

return 0;

}

@holzschu
Copy link
Owner

I don't know if that answers your question, but I've compiled nnn to WebAssembly. It will be in the next version of a-Shell (within a few days in TestFlight version, with a few weeks on the AppStore). I'll let you know when it's available. Also in the next version of a-Shell: ncurses (compiled to WebAssembly), which will greatly help in porting other programs.

@woncheol-kim
Copy link
Author

Amazing! Thanks!

@holzschu
Copy link
Owner

The TestFlight version of a-Shell mini with nnn included is here: https://testflight.apple.com/join/REdHww5C
I couldn't make it "edit" files (e) or display file details (f), but you can view the file (right arrow or l) and opent it in another app (o).

@woncheol-kim
Copy link
Author

thank you. this is a really promising progress!

I have found three bugs of nnn so far:

  • it does not display files with Korean file names ( or probably any other double byte characters )
  • file copy or move does not work
  • When making a new file, Canceling from prompt by escape key does not work

@holzschu
Copy link
Owner

holzschu commented Jun 4, 2024

Hi, thank you for raising all these points. There's a new a-Shell version out on TestFlight. It displays file names with UTF-8 characters, it has better copy and move (that one was tricky: the previous version was launching "cp", but asking for confirmation in an invisible screen. The new one asks for confirmation using hacks). I'm not sure about the issue with the escape key.

@woncheol-kim
Copy link
Author

woncheol-kim commented Jun 5, 2024

Thanks. I’ve just tested it and observed the following issues:

  • File copy or move operations still fail and result in an error message saying “failed.”
  • It displays files with Korean file names, but there are some bugs depending on the OS:
    • On macOS Sonoma 14.5 with an M1 chip, it works fine.
    • On iOS 17.5.1, some file names are not displayed correctly, but the open function works fine.
    • On visionOS, some file names are not displayed correctly and the open function does not work.

I haven’t had enough time to test with various file names yet, but it seems characters including ‘ㅇ’ may be causing problems.

An example of a file name:
통장 사본 (계좌 확인서).pdf (: original file name)
(계좌 확).pdf (:file name displayed on nnn for a-Shell mini)

On second thought, the ‘jongseong’ of Korean characters might actually be causing this issue. Please refer to the following quotes from Wikipedia:

https://en.wikipedia.org/wiki/Hangul

Morpho-syllabic blocks

Except for a few grammatical morphemes prior to the twentieth century, no letter stands alone to represent elements of the Korean language. Instead, letters are grouped into syllabic or morphemic blocks of at least two and often three: a consonant or a doubled consonant called the initial (초성, 初聲 choseong syllable onset), a vowel or diphthong called the medial (중성, 中聲 jungseong syllable nucleus), and, optionally, a consonant or consonant cluster at the end of the syllable, called the final (종성, 終聲 jongseong syllable coda). When a syllable has no actual initial consonant, the null initial ㅇ ieung is used as a placeholder. (In the modern Korean alphabet, placeholders are not used for the final position.) Thus, a block contains a minimum of two letters, an initial and a medial. Although the Korean alphabet had historically been organized into syllables, in the modern orthography it is first organized into morphemes, and only secondarily into syllables within those morphemes, with the exception that single-consonant morphemes may not be written alone.

The sets of initial and final consonants are not the same. For instance, ㅇ ng only occurs in final position, while the doubled letters that can occur in final position are limited to ㅆ ss and ㄲ kk.

Not including obsolete letters, 11,172 blocks are possible in the Korean alphabet.[77]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants