fox0430 / moe

A command line based editor inspired by Vim. Written in Nim.
https://editor.moe
GNU General Public License v3.0
648 stars 34 forks source link

support for map command #1249

Open leetschau opened 3 years ago

leetschau commented 3 years ago

Hi, @fox0430

I am very interested in this project as a fan of both nim and vim. After some searching, looks that there's no map, nnoremap, vnoremp, etc implemented in moe by far. I'd like to try to implement this feature if it hasn't yet.

I have a long coding experience as a Python developer, and have written some nim codes, but new to moe. Could you please give me some suggestions(or document list, roadmap) to implement this? Thanks!

fox0430 commented 3 years ago

@leetschau

Thank you for your interest in this project! Currently, does not exist documents for developers. But, I want to support you. Ask me anything!

At first, I recommend checking src/moepkg/normalmode.nim.

leetschau commented 3 years ago

To figure out how the codes running, I run the following command in terminal no.1:

nim c --debugger:native src/moe.nim
gdbserver :12345 src/moe

Then in terminal no.2, run:

gdb src/moe
(gdb) target remote localhost:12345
(gdb) b src/moepkg/normalmode.nim:427
(gdb) c

However, now on terminal no.1, there will be a text line Detaching from process 15882 printed out. And the TUI of moe is messed up.

How to hide irrelevant messages to keep TUI clean, so I can interact with moe in terminal no.1, and debug it in terminal no.2?

Or is there a better way to debug moe?

Thanks!

fox0430 commented 3 years ago

@leetschau

I usually don't use gdb, but please try this

./src/moe

Then in terminal no.2, run:

gdb -p <PID>
(gdb) b src/moepkg/normalmode.nim:427
(gdb) c

Alternatively, you can use the printf debug

Example

proc normalMode*(status: var EditorStatus) =
  if not status.settings.disableChangeCursor:
    changeCursorType(status.settings.normalModeCursor)

  ## printf debug ##
  exitUi()
  echo  status.settings.normalModeCursor  

If you want to check the output, quit moe or quit UI with the :! command.

And, you can also use logs

Example

proc normalMode*(status: var EditorStatus) =
  if not status.settings.disableChangeCursor:
    changeCursorType(status.settings.normalModeCursor)

  ## Write to log ##
  status.messageLog.add(($status.settings.normalModeCursor).toRunes)

If you want to check the output, you can check with :log command.

leetschau commented 3 years ago

Thanks for explanations, @fox0430

After reading the codes, seems that adding if settings["Standard"].contains("map"): in proc parseSettingsFile* can be the entrance of map configuration. But I didn't find this function called outside settings.nim.

So I try to figure out the calling sequences from the application start. I added some echo with different number to mark the calling sequences:

src/moe.nim:

proc initEditor(): EditorStatus =
  echo "=== 2 ==="
  let parsedList = parseCommandLineOption(commandLineParams())
  echo "=== 3 ==="

  defer: exitUi()
  echo "=== 4 ==="

  startUi()
  echo "=== 5 ==="

  result = initEditorStatus()
  echo "=== 6 ==="
  result.loadConfigurationFile
  echo "=== 7 ==="
  result.timeConfFileLastReloaded = now()
  result.changeTheme

src/moepkg/ui.nim:

proc setCursor*(cursor: bool) =
  echo "=== 4.4.1 ==="
  echo "cursor:" & $cursor
  if cursor == true: curs_set(1)      ## enable cursor
  elif cursor == false: curs_set(0)   ## disable cursor

...

proc startUi*() =
  # Not start when running unit tests
  when not defined unitTest:
    discard setLocale(LC_ALL, "")   # enable UTF-8

    echo "=== 4.1 ==="
    initscr()   ## start terminal control
    echo "=== 4.2 ==="
    cbreak()    ## enable cbreak mode
    echo "=== 4.3 ==="
    nonl();     ## exit new line mode and improve move cursor performance
    echo "=== 4.4 ==="
    setCursor(true)
    echo "=== 4.5 ==="

    if can_change_color():
      ## default is dark
      echo "=== 4.6 ==="
      setCursesColor(ColorThemeTable[ColorTheme.dark])

    echo "=== 4.7 ==="
    erase()
    echo "=== 4.8 ==="
    keyEcho(false)
    echo "=== 4.9 ==="
    set_escdelay(25)

Compile and run moe and quit with :q, the output are as follows:

$ nim c -r src/moe
=== 1 ===
=== 2 ===
=== 3 ===
=== 4 ===
=== 4.1 ===
=== 4.2 ===
           === 4.3 ===
                      === 4.4 ===
                                 === 4.4.1 ===
                                              cursor:true
=== 4.4.1 ===
cursor:false

My questions are:

  1. Does codes after setCursor(true) in startUi* executed? (mark 4.5 ~ 4.9 in startUi(), and 5 ~ 7 in initEditor())
  2. If they have been executed, why the output can't be seen in the console?
  3. I also added some echo in parseSettingsFile*, but they can't be seen, too. Is this function executed?
  4. If parseSettingsFile* hasn't been executed, as a moe user (instead of a developer), what he should do in moe TUI to make this function run?

Thanks!

fox0430 commented 3 years ago

@leetschau

  1. Yes. It will be executed.
  2. Can't print standard output after start ncurses UI (ncurses UI breaks or clear by ncurses). But, I don't know why can't print standard output after setCursor(true) (ncurses.curs_set(1)) not ncurses.initscr() ... So, Need to exit ncurses before echo(). Exit using exitUi() or ncurses.endwin(). And, ncurses UI is auto restart when printing ncurses UI (You don't need to execute startUI()).

Please try this

src/moe.nim:

proc initEditor(): EditorStatus =
  echo "=== 2 ==="
  let parsedList = parseCommandLineOption(commandLineParams())
  echo "=== 3 ==="

  defer: exitUi()
  echo "=== 4 ==="

  startUi()

  ##### Important! #####
  exitUi()

  echo "=== 5 ==="

  result = initEditorStatus()
  echo "=== 6 ==="
  result.loadConfigurationFile
  echo "=== 7 ==="
  result.timeConfFileLastReloaded = now()
  result.changeTheme

src/moepkg/ui.nim:

proc setCursor*(cursor: bool) =
  echo "=== 4.4.1 ==="
  echo "cursor:" & $cursor
  if cursor == true: curs_set(1)      ## enable cursor
  elif cursor == false: curs_set(0)   ## disable cursor

...

proc startUi*() =
  # Not start when running unit tests
  when not defined unitTest:
    discard setLocale(LC_ALL, "")   # enable UTF-8

    echo "=== 4.1 ==="
    initscr()   ## start terminal control
    echo "=== 4.2 ==="
    cbreak()    ## enable cbreak mode
    echo "=== 4.3 ==="
    nonl();     ## exit new line mode and improve move cursor performance
    echo "=== 4.4 ==="
    setCursor(true)

    ##### The same as exitUi() #####
    endwin()

    echo "=== 4.5 ==="

    if can_change_color():
      ## default is dark
      echo "=== 4.6 ==="
      setCursesColor(ColorThemeTable[ColorTheme.dark])

    echo "=== 4.7 ==="
    erase()
    echo "=== 4.8 ==="
    keyEcho(false)
    echo "=== 4.9 ==="
    set_escdelay(25)

Please use :! or quit moe to check the output.

  1. parseSettingsFile() is only executed when the configuration file existing in ~/.config/moe/moerc.toml.
  2. Please put the config file in ~/.config/moe/moerc.toml.

    Don't hesitate to ask me anything!

leetschau commented 3 years ago

Hi @fox0430

When I run nimble test --verbose on my laptop, the following errors raised:

[Suite] Editor: Send to clipboad
xclip: -r: No such file or directory
    /home/leo/Documents/temp/moe/tests/teditor.nim(90, 21): Check failed: exitCode == 0
    exitCode was 1
    /home/leo/Documents/temp/moe/tests/teditor.nim(92, 43): Check failed: output[0 .. output.high - 1] == $str
    output[0 .. output.high - 1] was Error: target STRING not available
    $str was Clipboard test
  [FAILED] Send string to clipboard 1
xclip: -r: No such file or directory
    /home/leo/Documents/temp/moe/tests/teditor.nim(114, 21): Check failed: exitCode == 0
    exitCode was 1
    /home/leo/Documents/temp/moe/tests/teditor.nim(116, 43): Check failed: output[0 .. output.high - 1] == $str
    output[0 .. output.high - 1] was Error: target STRING not available
    $str was `````
  [FAILED] Send string to clipboard 2
xclip: -r: No such file or directory
    /home/leo/Documents/temp/moe/tests/teditor.nim(139, 21): Check failed: exitCode == 0
    exitCode was 1
    /home/leo/Documents/temp/moe/tests/teditor.nim(141, 43): Check failed: output[0 .. output.high - 1] == $str
    output[0 .. output.high - 1] was Error: target STRING not available
    $str was $Clipboard test
  [FAILED] Send string to clipboard 3

However, PR #1285 passed the unit tests on Github. I'm trying to figure out why unit tests can't pass on my laptop. Looks like the problem is about xclip -r. The test command in tests/teditor.nim is:

execCmdEx("xclip -o")

Why it became to xclip -r when test running?

P.S.: The OS of my laptop is Linux Mint 19 (based on Ubuntu 18.04). The version of xclip is:

$ apt list --installed|grep xclip
xclip/bionic,now 0.12+svn84-4build1 amd64 [installed]

Thanks!

fox0430 commented 3 years ago

@leetschau

Currently using xclip -r when writing to the clipboard on Linux. https://github.com/fox0430/moe/blob/aba00768939af8295f555e168f1ccef448981a34/src/moepkg/editor.nim#L689

If you want to run it on Ubuntu, You need to install xclip v0.13.

Please check GitHub Actions flow. https://github.com/fox0430/moe/blob/aba00768939af8295f555e168f1ccef448981a34/.github/workflows/actions.yaml#L60-L64

I can't immediately remember why I'm using xclip -r, but if you know you don't need it, please let me know.

Thanks!

leetschau commented 3 years ago

According to xclip 0.13 man page, -r means "when the last character of the selection is a newline character, remove it".

However, there isn't -r option in version 0.12, which is installed with apt in Ubuntu 18.04 repository.

Maybe a version specification (something like >=0.13) of xclip in the "Requires" section of README is necessary, or use some other apps with more stable API (such as xsel) instead of xclip.

fox0430 commented 3 years ago

@leetschau

Thank you for your advice. I will edit README.md and take using other apps into consideration.