Skip to content

Commit 614bf29

Browse files
committed
feat(command): open external editor command in composing message
OPEN_EXTERNAL_EDITOR command paste the composing message in a python tempfile, run external editor over it and wait the exit before update the message. $ZULIP_EDITOR_COMMAND and fallback $EDITOR are use for the external editor command.
1 parent b81f30f commit 614bf29

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

docs/hotkeys.md

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
|Autocomplete @mentions, #stream_names, :emoji: and topics|<kbd>ctrl</kbd> + <kbd>f</kbd>|
8282
|Cycle through autocomplete suggestions in reverse|<kbd>ctrl</kbd> + <kbd>r</kbd>|
8383
|Narrow to compose box message recipient|<kbd>meta</kbd> + <kbd>.</kbd>|
84+
|Open the message in external editor|<kbd>ctrl</kbd> + <kbd>o</kbd>|
8485
|Jump to the beginning of line|<kbd>ctrl</kbd> + <kbd>a</kbd>|
8586
|Jump to the end of line|<kbd>ctrl</kbd> + <kbd>e</kbd>|
8687
|Jump backward one word|<kbd>meta</kbd> + <kbd>b</kbd>|

zulipterminal/config/keys.py

+5
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,11 @@ class KeyBinding(TypedDict):
310310
'help_text': 'View user information (From Users list)',
311311
'key_category': 'general',
312312
},
313+
'OPEN_EXTERNAL_EDITOR': {
314+
'keys': ['ctrl o'],
315+
'help_text': 'Open the message in external editor',
316+
'key_category': 'msg_compose',
317+
},
313318
'BEGINNING_OF_LINE': {
314319
'keys': ['ctrl a'],
315320
'help_text': 'Jump to the beginning of line',

zulipterminal/ui_tools/boxes.py

+31
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
UI boxes for entering text: WriteBox, MessageSearchBox, PanelSearchBox
33
"""
44

5+
import os
56
import re
7+
import shutil
8+
import subprocess
69
import unicodedata
710
from collections import Counter
811
from datetime import datetime, timedelta
12+
from tempfile import NamedTemporaryFile
913
from time import sleep
1014
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple
1115

@@ -810,6 +814,33 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
810814
elif is_command_key("MARKDOWN_HELP", key):
811815
self.view.controller.show_markdown_help()
812816
return key
817+
elif is_command_key("OPEN_EXTERNAL_EDITOR", key):
818+
editor = os.environ.get("ZULIP_EDITOR_COMMAND", os.environ.get("EDITOR"))
819+
if editor is None:
820+
self.view.controller.report_error(
821+
"Configure $EDITOR or $ZULIP_EDITOR_COMMAND shell environment."
822+
)
823+
return key
824+
editor_splits = editor.split(" ")
825+
fullpath_program = shutil.which(editor_splits[0])
826+
if fullpath_program is None:
827+
self.view.controller.report_error(
828+
"Editor program not found, check $EDITOR "
829+
"or $ZULIP_EDITOR_COMMAND."
830+
)
831+
return key
832+
editor_splits[0] = fullpath_program
833+
edit_tempfile = NamedTemporaryFile(suffix=".md")
834+
with open(edit_tempfile.name, mode="w") as edit_writer:
835+
edit_writer.write(self.msg_write_box.edit_text)
836+
self.view.controller.loop.screen.stop()
837+
editor_splits.append(edit_tempfile.name)
838+
subprocess.call(editor_splits)
839+
with open(edit_tempfile.name, mode="r") as edit_reader:
840+
self.msg_write_box.edit_text = edit_reader.read().rstrip()
841+
edit_tempfile.close()
842+
self.view.controller.loop.screen.start()
843+
return key
813844
elif is_command_key("SAVE_AS_DRAFT", key):
814845
if self.msg_edit_state is None:
815846
if self.compose_box_status == "open_with_private":

0 commit comments

Comments
 (0)