antonmedv / codejar

An embeddable code editor for the browser 🍯
https://medv.io/codejar/
MIT License
1.8k stars 116 forks source link

[Feature Request] Multiline Indentation with Tab Key #97

Open StevenEWright opened 1 year ago

StevenEWright commented 1 year ago

@antonmedv

It appears https://github.com/antonmedv/codejar/issues/64 was closed as complete, but I don't think this feature exists in codejar.

If you're open to it, I may be willing to contribute the feature, but I wanted to ask your opinion before I bothered.

Is this something codejar would like to have, and would you be open to a PR for it?

Thanks,

Steve

antonmedv commented 1 year ago

This feature seems very complicated. I think there are a lot of things to do. For example, improve the handling of newline in empty editor.

StevenEWright commented 1 year ago

Could you elaborate on why you think it may be complicated?

It seems like a relatively straight forward change to the tab handling routine to simply iterate over the selected lines and insert (or remove, if it's shift-ed) a tab character from the beginning of each line. Is there some complexity to it I'm missing?

Please let me know if this is something you'd be willing to work with me on if I send you a PR or if you'd prefer to focus your time on other things like the newline problems.

Thanks for the response!

Steve

antonmedv commented 1 year ago

Check it in chrome,safari and firefox.

julianpoemp commented 1 year ago

perhaps a solution could be:

1) Get raw code of selected HTML 2) Apply multiline indentation on raw code (for each line prefix with tab). 3) Apply highlighting on raw code => new HTML code 4) Replace selected HTML with new HTML code.

Am I missing something?

Edit: Perhaps the problem could be to find the start and end position of selected HTML if the selection starts/ends between the start and/or end line.

panoply commented 1 year ago

This feature seems very complicated. I think there are a lot of things to do.

@antonmedv This can sometimes be a tad extraneous when loc sizes are in the thousands.

Perhaps the problem could be to find the start and end position of selected HTML if the selection starts/ends between the start and/or end line.

@julianpoemp You can just leverage the existing logic. Based on what I quickly browsed over in the source for CodeJar, the below should work for a few hundred loc~line. Supports dedent and indent.

Someone should test.

EDIT 1

Consider moving around tab Indent handler


/* add with the keydown event, in codejar that is here */

on('keydown', (event) => {

    // other code .....

   // pass directly after the options.history recording,
   handleMultilineIndent(event)

})

/*  the multiline tab indent */
function handleMultilineIndent (event: KeyboardEvent) {

    if (event.key === 'Tab') {

      event.preventDefault();

      // Obtain selection
      const sel = getSelection().getRangeAt(0).toString();  
       // Newlines
      const nwl = sel.split('\n');  
      // Cached length 
      const itm = nwl.length;

      let len = 0; // Holds the increment/decrement for restore()

      if (event.shiftKey) { // Dedent, ie: shift + tab

         const pos = save();  // Save pos

        for (let i = 0; i < itm; i++) {

          // We want the padding upto the first non whitespace character
         // while regex here is a little extraneous it suffices.
          const space = nwl[i].slice(0, nwl[i].search(/\S/));

          // Handle dedents
          if (space.length > options.tab.length) {
            nwl[i] = nwl[i].slice(options.tab.length);
            len = len + options.tab.length;
          } else if (options.tab.length > 0) {
            len = len + 1;
            nwl[i] = nwl[i].slice(1);
          }

        }

        insert(nwl.join('\n'));  // Rejoin

        if (pos.dir === '->') {
          restore({ start: pos.start - len, end: pos.end });
        } else {
          restore({ start: pos.start, end: pos.end - len });
        }

      } else {

       // Tab indent on multiline
       const pos = save();

        for (let i = 0; i < itm; i++) {
          nwl[i] = options.tab + nwl[i];
          len = len + options.tab.length;
        }

        insert(nwl.join('\n'));

        if (pos.dir === '->') {
          restore({ start: pos.start + len, end: pos.end });
        } else {
          restore({ start: pos.start, end: pos.end + len });
        }
      }

    }
  }
StevenEWright commented 1 year ago

@panoply Thank you for the jump-start. Please checkout my PR - I'd be interested in hearing your thoughts on the Firefox situation.