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

Implement cursor movement in unix_formatting #553

Closed
3 tasks done
jcubic opened this issue Dec 29, 2019 · 43 comments
Closed
3 tasks done

Implement cursor movement in unix_formatting #553

jcubic opened this issue Dec 29, 2019 · 43 comments
Labels
feature resolved if issue is resolved, it will be open until merge with master

Comments

@jcubic
Copy link
Owner

jcubic commented Dec 29, 2019

I have idea for a new feature for jQuery Terminal

I've already stared in unix_formatting.js#L517 but the parser have issues. This one is first version of the code, since then it was updated. Was not able to fix it myself and I've asked on StackOveflow: How to parse cursor ANSI escape codes?

  • Add basic cursor movement
  • Working SIXEL example
  • Add H escape code
@jerch
Copy link

jerch commented Dec 29, 2019

Any chance that you are running the ervy lib directly without a pty in between? If so, you prolly have to replace every LF ('\n') with CR-LF ('\r\n'). (Thats one of the transformations a tty typically does.)

If this doesnt help, maybe post the stream data as JSON string here.

@jcubic
Copy link
Owner Author

jcubic commented Dec 29, 2019

Here is the output of the plot:
" Y Axis A: \u001b[31m*\u001b[0m | B: \u001b[34m# \u001b[0m | C: \u001b[36m@ \u001b[0m\n\n\u001b[0C\u001b[0A \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[0C \n\u001b[5C\u001b[1A\u001b[31m*\u001b[0m\n\u001b[1B\u001b[7C\u001b[2A\u001b[31m*\u001b[0m\n\u001b[2B\u001b[9C\u001b[3A\u001b[31m*\u001b[0m\n\u001b[3B\u001b[11C\u001b[4A\u001b[31m*\u001b[0m\n\u001b[4B\u001b[13C\u001b[5A\u001b[31m*\u001b[0m\n\u001b[5B\u001b[15C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[17C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[19C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[21C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[23C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[25C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[27C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[29C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[31C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[33C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[35C\u001b[6A\u001b[31m*\u001b[0m\n\u001b[6B\u001b[7C\u001b[6A\u001b[34m# \u001b[0m\u001b[34m# \u001b[0m\n\u001b[7C\u001b[34m# \u001b[0m\u001b[34m# \u001b[0m\n\u001b[6B\u001b[3C\u001b[0A\u001b[36m@ \u001b[0m\n\u001b[0B\u001b[30D\u001b[11A A\n 10|\n |\n 8|\n |\n 6|\n |\n 4|\n |\n 2|\n |\n |\u001b[1D+---+---+---+---+---+----+----+----+-> X Axis\n 0 2 4 6 8 10 12 14 "

\r is ignored by my library and \n is working like on Linux.

@jcubic
Copy link
Owner Author

jcubic commented Dec 29, 2019

I think I know what the problem is:

{s: "   A", x: -26, y: 2, line: "   A                                  "}
``
what should negative cursor do? I've tried to set it to 0 and y--.

@jerch
Copy link

jerch commented Dec 29, 2019

Ah ok, well those cursor movement sequences always stick to 0 (left/top) or (cols/rows)-1 (given that your coords are 0 based). They also would never flip over to a next/previous line, they simply stop at the border they would pass:

  • CSI 99999 ; 99999 H would stop at the rightmost cell in the bottom line (given the terminal is smaller)
  • CSI 99999 D would stop at the leftmost cell, no line switch

@jcubic
Copy link
Owner Author

jcubic commented Dec 29, 2019

This is my latest code also did mistake in if (!line) case where cursor.x > 0

var terminal = {
    inst_p: function(s) {
        var line = result[cursor.y];
        if (!line) {
            if (cursor.x > 0) {
                result[cursor.y] = new Array(cursor.x + 1).join(' ') + s;
            } else {
                result[cursor.y] = s;
            }
        } else if (cursor.x === 0) {
            result[cursor.y] = s + line.substring(s.length);
        } else if (line.length < cursor.x) {
            var len = cursor.x - (line.length - 1);
            result[cursor.y] += new Array(len).join(' ') + s;
        } else if (line.length === cursor.x) {
            result[cursor.y] += s;
        } else {
            var before = line.substring(0, cursor.x);
            var after = line.substring(cursor.x + s.length);
            result[cursor.y] = before + s + after;
        }
        cursor.x += s.length;
        console.log({s, ...cursor, line: result[cursor.y]});
    },
    inst_o: function(s) {console.log('osc', s);},
    inst_x: function(flag) {
        var code = flag.charCodeAt(0);
        if (code === 10) {
            cursor.y++;
            cursor.x = 0;
        }
        console.log('newline');
    },
    inst_c: function(collected, params, flag) {
        console.log({collected, params, flag});
        var value = params[0] === 0 ? 1 : params[0];
        switch(flag) {
            case 'A': // UP
                cursor.y -= value;
                break;
            case 'B': // Down
                cursor.y += value - 1;
                break;
            case 'C': // forward
                cursor.x += value;
                break;
            case 'D': // Back
                cursor.x -= value;
                break;
            case 'E': // Cursor Next Line
                cursor.x = 0;
                cursor.y += value;
                break;
            case 'F': // Cursor Previous Line
                cursor.x = 0;
                cursor.y -= value;
                break;
        }
        if (cursor.x < 0) {
            cursor.x = 0;
        }
    },
    inst_e: function(collected, flag) {console.log('esc', collected, flag);},
    inst_H: function(collected, params, flag) {console.log('dcs-Hook', collected, params, flag);},
    inst_P: function(dcs) {console.log('dcs-Put', dcs);},
    inst_U: function() {console.log('dcs-Unhook');}
};

if I remove that -1 the plot is broken completely. looks weird that's there.

@jerch
Copy link

jerch commented Dec 29, 2019

I dont see where you limit the cursor access to the bottom, I think those cursorDown sequences with high params will keep enlarging result to the bottom. The -1 seems to partly fix that (but in a wrong way). Does it work if you replace that line with cursor.y = Math.min(cursor.y + value, result.length - 1);? (Assuming the lib expects to write its plot at the bottom, the cursor can never go beyond the last line).

Edit: Yepp, this seems to be a bug in the ervy lib - if I remove the other examples from their demo, the scatter plot gets screwed up like this a maximized and cleared terminal (tested with xterm):

grafik

So there are two issue behind this:

  • ervy lib expects always to write at the bottom of a terminal viewport, but thats not always the case (so your code is right about that behavior)
  • you should limit cursor access also to the right and bottom (kinda like spanning a canvas where the cursor can be moved in), only overflows at the bottom line in inst_p and '\n' are allowed to scroll (means your "canvas frame" would move one line down in result, thus the very first line is not accessible anymore by cursor movements and so on)

@jcubic
Copy link
Owner Author

jcubic commented Dec 29, 2019

It seems that this works, cursor.y = Math.min(cursor.y + value, result.length); so it can move to next line but not more.

@jerch
Copy link

jerch commented Dec 29, 2019

Eww moving to the next line to the bottom should not work by cursor movement sequences, only overflow+wrap in PRINT or explicit NL at the bottom line should scroll the terminal viewport. I am not sure if ervy is a good test candidate here as it seems to have this bug above.

Note that some apps using the terminal more as text canvas might do exessive CUD and CUF just to get the cursor at the bottom line or rightmost cell without caring for the actual viewport size and printing from there backwards. Thus I think you should declare a cursor adressible area (viewport in COLS/ROWS), that would scroll relative to result offset on print wrapping or NL in the bottom line.

@jcubic
Copy link
Owner Author

jcubic commented Dec 30, 2019

But why XTerm work properly, is it detecting malformed output? What about xterm.js? You said that with TTY it work correctly with ervy plot.

@jerch
Copy link

jerch commented Dec 30, 2019

But why XTerm work properly, is it detecting malformed output? What about xterm.js?

No, ervy does not work correctly in xterm if the terminal window is maximized and cleared before running a scatter plot. As far as I can tell from the sequences sent by ervy they kinda draw the plot with excessive CUD sequences, which moves the cursor too far to the bottom screwing up the plot (see the image above). Thats a bug in ervy, xterm does no special error correction here, it just draws what it was told. Same with xterm.js (xterm and xterm.js show the same output).

You said that with TTY it work correctly with ervy plot.

Not sure where I said that. Regarding the sequences involved in the plot output the TTY only would do the LR --> CRLF transformation, which is not needed if you do it in the terminal yourself. I dont see any other control codes, that would be affected by the TTY. Note that a TTY does not deal with multibyte sequences at all, it simply forwards those to the terminal. (TTYs are getting complicated, when the user inputs data, but thats not the case here.)

I dont know your internal terminal design, most likely you already have a row/cols limited "viewport" (+ some scrollback). Isn't it easier to just reposition the cursor within that area and let the print happen by your already established output/print methods?

@jcubic
Copy link
Owner Author

jcubic commented Dec 30, 2019

Uh, sorry I was not using Xterm but xfce4-terminal and there it works even if I render single scatter plot if taller terminal. But that terminal is fixing the errors. I need to check this terminal source code. Maybe I'll find some clue how it's handled.

Not sure where I said that.

You said that xterm works the same as in xterm.js I've assume that it was correct. I've maybe I've interpreted this wrong.

@jcubic
Copy link
Owner Author

jcubic commented Dec 30, 2019

dont know your internal terminal design

In my terminal the cursor is independent of the output, so I have cursor inside string to format ANSI escapes I need single string as output.

Also my terminal is not TTY it have nothing to do with Linux, the library is mainly used to create command line apps purely in the browser. If someone need tty I suggest xterm.js.

@jerch
Copy link

jerch commented Dec 30, 2019

Uh, sorry I was not using Xterm but xfce4-terminal and there it works even if I render single scatter plot if taller terminal.

Well I only tested their demo scatter plot with other outputs disabled . xfce-terminal looks exactly the same as the xterm output above. Again, thats an ervy bug, nothing a terminal can do about it.

You said that xterm works the same as in xterm.js I've assume that it was correct. I've maybe I've interpreted this wrong.

Ah yes, in the other post. Well that was meant for the screwed up image you posted there, which I wasnt able to repro. If I run it in xterm.js demo (with a pty in between), it outputs the same as xterm and xfce-terminal (including the buggy plot in maximized and cleared terminal).

In my terminal the cursor is independent of the output, so I have cursor inside string to format ANSI escapes I need single string as output.

Well I guess I cant help you here, seems to be quite different to the classical text grid + cursor movements semantics of other terminals.

Also my terminal is not TTY it have nothing to do with Linux, the library is mainly used to create command line apps purely in the browser. If someone need tty I suggest xterm.js.

Btw a TTY as a hardware device is just what a typewriter would do - advance the cursor with input and handle basic control codes like CR + LF, BS, TAB and such. In that sense xterm.js is a TTY, as it also resembles that functionality. And your terminal doesnt?

Note that the meaning of TTY goes beyond that in Unix/POSIX - it originally denoted a piece of hardware (a real tty or a video terminal) + process I/O and controlling functions from the OS. Thus a process would not write/read directly from a terminal buffer, but always stream STDIN and STDOUT as bytes from/to the terminal (The early devices had not even anything like a buffer beside a piece of paper or punchcards). The kernel driver sits in between to enable interrupt handling / signalling (+ some byte transformations). When I refer to pty/tty I typically mean only the kernel driver part, due to the pseudoterminal interface (PTY/PTS) the terminal part is not important anymore as any process can act as such. (Im pretty sure that your terminal could as well with only minor modifications).

@jcubic
Copy link
Owner Author

jcubic commented Dec 30, 2019

Thanks, for explanation, your correct the ervy is broken if run the code in clear terminal. I tested with lot of output in terminal with that it was working. But on clear terminal without any output it give the same output as your screen. Thanks for your help, will file a bug in ervy.

@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

@jerch I was able to create proper cursor handling and simplify the code using your parser. Had issue with one ANSI art, but I was able to solve the issue. Thanks.

@jcubic jcubic closed this as completed Jan 1, 2020
@jcubic jcubic reopened this Jan 1, 2020
@jcubic jcubic added feature resolved if issue is resolved, it will be open until merge with master labels Jan 1, 2020
jcubic added a commit that referenced this issue Jan 1, 2020
jcubic added a commit that referenced this issue Jan 1, 2020
@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

@jerch one more question, it works for ansi art but the output of ervy don't look like on clear terminal. What Should negative cursor.y do? Should it create new line above or just reset to 0. I use cursor.y = 0 but it don't looks correct.

@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

Ok, it's working, had typo cursor.y = value instead += value. It work the same as in clear terminal.

jcubic added a commit that referenced this issue Jan 1, 2020
@jerch
Copy link

jerch commented Jan 1, 2020

Ok, it's working, had typo cursor.y = value instead += value. It work the same as in clear terminal.

Guess this depends on how much you want to resemble ANSI terminals here. A real ANSI terminal would also restrict the right side and the bottom like this:

// restrict to bottom
cursor.y = Math.min(cursor.y + value, MAX_ROWS - 1);
// restrict to right
cursor.x = Math.min(cursor.x + value, MAX_COLS - 1);

If you dont want that restriction - just be aware that "drawing" from right side or from bottom will behave differently than in any other ANSI terminal:

// move cursor to rightmost cell in line
CUF(9999999);
// go 2 cells back
CUB(2);
// put something in last two cells of line
print('xy');

In an ANSI terminal 'xy' would always stick to the last 2 cells, no matter how wide the terminal is. Without the line restriction you'll get a line like ' '.repeat(9999997) + 'xy'.

Edit: To make this even more complicated - a DEC VT line compatible emulator would also have to respect scroll margins (top/bottom/left/right), depending on the emulation level. Those margins are by default set to the viewport size, but can be changed throught DEC sequences. I think you dont need to respect those, as it would pull in tons of other DEC VT awkwardities. xterm.js currently only supports top/bottom scroll margins. (left/right is still an open issue)

@jerch
Copy link

jerch commented Jan 1, 2020

@jerch one more question, it works for ansi art but the output of ervy don't look like on clear terminal. What Should negative cursor.y do? Should it create new line above or just reset to 0. I use cursor.y = 0 but it don't looks correct.

Sorry, just saw that question.

Well to get the same as the broken ervy output in other terminals, you will not get around the "canvas" thing I noted above with the right/bottom limits. Also negative is not possible (cursor cannot pass top/left border).

To not pull in a full ANSI terminal clone into your terminal, something like this might work:

  • create a cell canvas in the current size of your terminal, e.g. as 2-dim array like canvas = [new Array(COLS-1), ...ROWS-1] --> canvas,join('\n') would return an empty "sheet" (optional with whitespace as cell placeholders)
  • figure out current cursor position in your emulator --> move cursor in the canvas at that position
  • drawing now begins from that cursor position
  • clamp cursor movements in the canvas area at every border (no negative positions, no position beyond right/bottom border allowed)
  • if a scroll is requested ('\n' or wraparound from PRINT happened in bottom line) -> append one line to the canvas + offset cursor y by one (thats important - after a scroll the cursor cannot access scrolled out lines at the top anymore)
  • PRINT now is just a canvas[cursor.y][cursor.x++] = c for a single character, whenever the cursor hits the last cell in line, you would wraparound to the next line (cursor.y++; cursor.x = 0;), if cursor.y would end up at a non existant line (beyond bottom line), you'd scroll (see above)

Now when the drawing is finished, you can clip the canvas content into your terminal. Any cell that has content would have overwritten stuff in your terminal view, any empty cell is a NOOP.

Edit: Btw, you might also want to implement CUP (CSI H) for absolute cursor positioning. This sequence is often used for drawing stuff. With the canvas above its as simple as that:

inst_c(params, ...) {
    ...
    case 'H':
        cursor.y = Math.min(params[0] || 1, ROWS) - 1; // -1 since CUP is 1-based
        cursor.x = Math.min(params[1] || 1, COLS) - 1;
        break;
}

@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

Thanks again for your pointers, If I find some ANSI art that is broken maybe I will add more compatibility with real ANSI terminal including H escape code.

H will be problematic. I think ANSI art only use relative cursor movement (just like ervy but in buggy way). The problem in terminal is that the code for ANSI escapes is like language transpiler it should know nothing about real terminal, it's pure function, I could access terminal that use the function, but it should also work outside of terminal.

The boundary of cols/rows in my case is input string and lines that are generated by ANSI codes. I think that H should work differently it should modify previous stuff on terminal. It will only work If will alow to move the cursor inside single input string. Like in CSS if I use position: relative on whole input string and use absolute but only relative the string. But this probably will be incompatible with ANSI terminal so I think that I will just ignore other codes.

@jerch
Copy link

jerch commented Jan 1, 2020

H will be problematic. I think ANSI art only use relative cursor movement (just like ervy but in buggy way).

Well the problem here is what you see as "ANSI art" and were to stop to implement ANSI escape sequences. I for myself cannot answer that even for xterm.js. This already was a problem back in the 80s, DEC solved this for their own terminals with the "emulation levels", but thats orthogonal to any official spec (ANSI even dropped terminal sequences later on, and just referred to ECMA-48). In xterm.js we dont follow those DEC emulation levels at all, we simply go with whatever was requested and fits into the bigger picture (xterm.js is currently a mixture of DEC level 1-4 emulation + some ECMA-48 sequences). Thus we only implement ~half of the sequences xterm understands. The other half is either ancient stuff we prolly never will support, or so rare in current apps that we never got an issue request for it. I think most popular emulators deal with sequences that way, only a few announce official full "emulation level" support. Yes - when it comes to a certain terminal sequence and the question whether it should be supported at all - its a total mess and cannot be answered easily.

All that said - I cannot tell you where it makes sense to stop dealing with ancient sequence XY. There is always a small chance that ANSI art xy from the 90s might use a sequence thats totally forgotten about. For a starter maybe the animations on vt100.net might be worth looking at (https://vt100.net/animation/).

@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

It works in xfce4-terminal, but fail on my terminal. But it have lot of H codes. Maybe I will implement those.

Right now I'm happy that it work for modern ANSI art from https://16colo.rs/ or this example: https://www.gnu.org/graphics/agnuheadterm.html

and that it will work as Demo for ervy when they fix the bug.

@jerch
Copy link

jerch commented Jan 1, 2020

Well your current code will work for any "ANSI art" that only uses relative cursor positioning from top/left. As soon as positioning from right/bottom or absolute is involved - it will fail for the reasons I mentioned above. From here on its kinda your decision whether to tell ppl to only use top/left relative positioning or fix it to support the other modes as well. I think without right/bottom + absolute repositioning you'll get tons of issue reports ;) (CUP is VERY common)

@jcubic
Copy link
Owner Author

jcubic commented Jan 1, 2020

Will add H escape code then. I think that there are not much users that use this feature. To this point I've only got bug report about backspace handling issues. My first code only supported over typing from man command, it didn't suport any backspace handling. Also I think that ANSI art is only something that live in one the demos, but of course I'm not sure if someone is not using this. The problem with H is that it will require the state from terminal, as I said my handling of ANSI escapes is stateless from outside. Also wrapping is handed in different place. Maybe if options will have COLS, it will work. And ROWS will be taken from internal state of single string.

@jcubic jcubic removed the resolved if issue is resolved, it will be open until merge with master label Jan 1, 2020
@jerch
Copy link

jerch commented Jan 1, 2020

I see. Well this sounds as if you will not face many issues from that at all. If I were you - I'd call this a nice to have feature with lazy support, thus stuff gets only fixed if I am either in the mood to do so or things fit into the whole picture easily (seems it doesn't atm). Everything beyond that cannot be expected to work.

@jerch
Copy link

jerch commented Jan 2, 2020

Slightly offtopic:
Just a wild idea - since you are about to add "ANSI graphics" - how about SIXEL support? Thats DEC's old pixel graphics format for terminals and printers, that has recently seen a renaissance and can be used by several REPLs for plot output.
You'll find a working prototype for JS here: https://github.com/jerch/node-sixel/blob/master/node_example_decode_full_sequence.js

@jcubic
Copy link
Owner Author

jcubic commented Jan 2, 2020

Do you have any article about this, maybe wikipedia page or examples how it looks like?

@jerch
Copy link

jerch commented Jan 2, 2020

Well ressources about this are very limited these days, the wiki page is kinda very short: https://en.wikipedia.org/wiki/Sixel

If you want to see it in action - there is my playground branch in xterm.js with a picture how it could look like in a terminal window: xtermjs/xterm.js#2503

@jcubic
Copy link
Owner Author

jcubic commented Jan 2, 2020

First quick intro: jQuery Terminal formatters (like unix formatter for ANSI escapes) are just text transformers it should output internal formatting that look like this [[b;#fff;]xxx] this main syntax of adding colors to terminal. It's easy to parse. There is one feature with this syntax which is @ inside first slot it will render an image.

Using this images with @ you can use your code render to canvas grab objectURL and put as output. It should be simple. But I think if anyone will want something like this can create Codepen demo for this.

I can only make it easer by adding hooks to your ANSI parser from outsite so users can overwrite the code, will need to think about this.

After consideration I think that I will play with this and see how to implement this outside of the library and expose what need to make user code shorter. Will try to create Codepen demo.

@jcubic
Copy link
Owner Author

jcubic commented Jan 2, 2020

I have more interesting question, do you know this library: blessed, and what it do to render the content of terminal? Just got asked if it's possible to support something like this.

@jerch
Copy link

jerch commented Jan 2, 2020

Ah well it was just an idea, also we still have some discussion going on in the terminal-wg how a good image support should look like. Once we get something rolling (hopefully we will lol), it most certainly would deprecate SIXEL (SIXEL has some major drawbacks compared to "modern" image formats).

I have more interesting question, do you know this library: blessed, and what it do to render the content of terminal? Just got asked if it's possible to support something like this.

Nope I dont know this library. Seems to be like a curses clone with slightly different API. curses apps typically use the terminal as canvas, and redraw stuff if needed. To accomplish this, they kinda have to provide their own "terminal buffer" in the app, and write differences to the terminal. For different terminal types they use terminfo to check for supported sequences by a certain terminal. Not sure if blessed also does that or would always assume some level of sequence support.

I cannot tell if thats easy to accomplish with your terminal, since I dont know anything about its API or internal structure. The lib itself seems to be unmaintained, I typically try not to rely on stuff like that.

@jcubic
Copy link
Owner Author

jcubic commented Jan 2, 2020

I've tested Sixel and it's really really slow, rendering single image 200px wide took few seconds and it's lot of effort when you can just render the image directly. I will expose the API to allow to create a way to parse Sixel (the same you will be able to implement H escape code without modifying the library) but I don't think it will be of any use. Also there are also 2 problems my formatter is synchronous and to generate objectURL (short in memory image) it require async call.

The same is with your parser is also not async, but that should not be a problem, if my formatter was async I would be able to write placeholder of image continue parsing and replace the placeholder with real blob Object URL. and resolve main promise when ll sixel images are resolved and converted to object URL.

The code that right don't work.

                      var y = this.cursor.y++;
                      this.cursor.x = 0;
                      this.result[y] = '[[;;]';
                      canvas.toBlob((blob) => {
                          var uri = URL.createObjectURL(blob);
                          this.result[y] = this.result[y].replace(/\[\[;;\]\]/, '[[@;;;;' + uri + ']]');
                      });

this don't work, but using normal canvas.toDataURL("image/png") that is sync works, but the data URI is big even for small images. Maybe that's why it's slow, or parsing is slow.

My ANSI formatter (like other formatters) that can be async is nice idea, first came to problem like this when I need async call.

I've build your library using webpack, just running ./node_modules/.bin/webpack built correct file.

The reason why it's slow because there is lot of data. 200px image is 40KB of text, that give hard time to the regular expressions inside the library, one function that just use regex to test if input text have formatting took 2 seconds to complete. Rendering that image took more then 10 seconds. I think that someone would like to render image like this he can first parse the text in memory and just output the blob Image. And the code would be simpler nothing need to be modified.

Will try this way and create demo that's faster and actually usable.

@jerch
Copy link

jerch commented Jan 2, 2020

Do you have a codepen for this so I can have a look? I put some effort into the libs performance, for me it renders a 800x600 image in under 10ms - so I guess there are some other things eating CPU cycles.

Edit: Btw you can test the lib directly in any SIXEL capable terminal like this:

$> node img2sixel.js -p16 http://leeoniya.github.io/RgbQuant.js/demo/img/bluff.jpg

You can run this in xterm if you start it with xterm -ti vt340. The example script though does encoding which is very expensive due to the needed quantization + dithering (one of the drawbacks of the format. The data packrate being another one - needs quite big data files.) Decoding on the other hand is quite speedy (fast enough for sync, if you need async, well just place the conversion into some callback.)

@jcubic
Copy link
Owner Author

jcubic commented Jan 3, 2020

The problem was with my library, I've added echo the text into terminal, which and given very hard time to the library. I've didn't tested processing with your library, probably it was executed at the end it was fast. This type of code need to be done outside of terminal. I'll try another API just for this, that executed before the text is processed by the library.

I have option renderHandler(obj) that is used to handle stuff that was put into echo, I hope that my library will not even see this text and need to run regexes on it.

@jcubic
Copy link
Owner Author

jcubic commented Jan 3, 2020

Working code of SIXEL outside of terminal using renderHandler https://codepen.io/jcubic/pen/WNbXdRg

works nice and fast. Need to expose the parser inside unix_formatting. So the code use devel branch.

jcubic added a commit that referenced this issue Feb 1, 2020
@jcubic
Copy link
Owner Author

jcubic commented Feb 1, 2020

@jerch one more question, can you tell me why animations from https://vt100.net/animation render lines in unix terminal? the file only have

\x1b[1mlqqqqqqqqqqqqqqqqqvvqqqqqqqqqqqqqqqqk\x1b[m

how this is processed? Is this \x1bL some kind of line character processing? I can't find it in docs:
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

@jerch
Copy link

jerch commented Feb 2, 2020

This looks like a line for the DEC supplemental charset. Terminals maintain several iso 2022 charsets and can switch between them through escape sequences. The handling is abit cumbersome, at least you might want to support the graphics charset (see https://github.com/xtermjs/xterm.js/blob/fbeb45d1da9960cb9ebb0fea56882128696a254b/src/common/data/Charsets.ts#L30).

@jcubic
Copy link
Owner Author

jcubic commented Feb 2, 2020

@jerch it seems that i will not implement this iso 2022 graphics characters, it's really obscure but does you ansi parser support ESC ( 0 code? I think that can use ( code.

@jcubic
Copy link
Owner Author

jcubic commented Feb 2, 2020

ok I've found it it's inst_e

@jcubic jcubic added the resolved if issue is resolved, it will be open until merge with master label Feb 2, 2020
@jerch
Copy link

jerch commented Feb 2, 2020

Yes inst_e handles those. The parser exposes these 5 sequence types:

  • ESC: inst_e
  • CSI: inst_c
  • OSC: inst_o
  • C0/C1 control codes: inst_x
  • DCS: inst_H, inst_P and inst_U

Everything else gets either swallowed (APC/SOS/PM are unsupported) or is directly printable (inst_p). Lol, my naming is abit strange (its a remnant of my old C parser).

Yupp, you most likely dont need all the ISO2022 stuff, its hardly used anymore. We also removed most things regard this in xterm.js, it implements only the basic charset switches.

@jcubic jcubic closed this as completed Feb 17, 2020
@jcubic
Copy link
Owner Author

jcubic commented Sep 10, 2020

@jerch hey do you have any experience with XBin or Bin files? They are ANSI images in binary form. https://en.wikipedia.org/wiki/XBin

@jerch
Copy link

jerch commented Sep 10, 2020

@jcubic Nope, but the spec seems pretty straight forward in case you want to implement it (https://web.archive.org/web/20120204063040/http://www.acid.org/info/xbin/x_spec.htm).

@jcubic
Copy link
Owner Author

jcubic commented Sep 10, 2020

Yes I wanted to play with it, but wanted to ask, so I don't write code if someone else already done this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature resolved if issue is resolved, it will be open until merge with master
Projects
None yet
Development

No branches or pull requests

2 participants