Change message composition, reply, and editing to external editor

This commit is contained in:
Eric B. Budd 2021-10-24 14:36:13 -05:00 committed by Eric Budd
parent 80d2c616ca
commit 79bc357828
2 changed files with 58 additions and 94 deletions

View File

@ -159,13 +159,13 @@ I'm trying to decide on a new place in the tildeverse to call home. Any ideas?
This allows you to add a new top-level topic to the board. The first line of your new topic will be used as the topic title. This allows you to add a new top-level topic to the board. The first line of your new topic will be used as the topic title.
The line editor is quite basic. Enter your message, line-by-line, and type a single period on a line by itself to end the message. Iris will allow you to type in your message in the editor you have defined in your shell with the `$EDITOR` environment variable.
If you post an empty message, the system will discard it. If you post an empty message, the system will discard it.
``` ```
jimmy_foo@ctrl-c.club~> compose jimmy_foo@ctrl-c.club~> compose
Writing a new topic. Type a period on a line by itself to end message. Writing a new topic.
new~> How do I spoo the fleem? new~> How do I spoo the fleem?
new~> It's not in the docs and my boss is asking. Any help is appreciated! new~> It's not in the docs and my boss is asking. Any help is appreciated!
@ -188,14 +188,13 @@ jimmy_foo@ctrl-c.club~> topics
Replies are responses to a specific topic -- they only appear when displaying the topic. Replies are responses to a specific topic -- they only appear when displaying the topic.
The line editor is quite basic. Enter your message, line-by-line, and type a single period on a line by itself to end the message. Iris will allow you to type in your message in the editor you have defined in your shell with the `$EDITOR` environment variable.
If you post an empty message, the system will discard it. If you post an empty message, the system will discard it.
``` ```
jennie_minnie@ctrl-c.club~> reply 3 jennie_minnie@ctrl-c.club~> reply 3
Writing a reply to topic 'How do I spoo the fleem?'. Writing a reply to topic 'How do I spoo the fleem?'.
Type a period on a line by itself to end message.
reply~> Simple, you just boondoggle the flibbertigibbet. That should be in the manual. reply~> Simple, you just boondoggle the flibbertigibbet. That should be in the manual.
reply~> . reply~> .
@ -229,7 +228,7 @@ A topic ID will always be strictly numeric, "3" in the following example.
The message or topic ID can be found in square brackets in the informational text above each message. The message or topic ID can be found in square brackets in the informational text above each message.
The line editor is quite basic. Enter your edited message, line-by-line, and type a single period on a line by itself to end the message. Iris will allow you to type in your message in the editor you have defined in your shell with the `$EDITOR` environment variable.
If you post an empty message, the system will discard it and the edit will be ignored. If you post an empty message, the system will discard it and the edit will be ignored.
@ -250,7 +249,6 @@ It's not in the docs and my boss is asking. Any help is appreciated!
jennie_minnie@ctrl-c.club~> edit M5 jennie_minnie@ctrl-c.club~> edit M5
Editing message 'Simple, you just boondoggle the flibbertigibbet. That shoul...' Editing message 'Simple, you just boondoggle the flibbertigibbet. That shoul...'
Type a period on a line by itself to end message.
edit~> Simple, you just boondoggle the flibbertigibbet. That's in the manual on page 45. edit~> Simple, you just boondoggle the flibbertigibbet. That's in the manual on page 45.
edit~> . edit~> .

142
iris.rb
View File

@ -4,6 +4,7 @@ require 'digest'
require 'etc' require 'etc'
require 'json' require 'json'
require 'readline' require 'readline'
require 'tempfile'
require 'time' require 'time'
# require 'pry' # Only needed for debugging # require 'pry' # Only needed for debugging
@ -687,21 +688,6 @@ class Interface
'unread' => 'unread', 'unread' => 'unread',
} }
def browsing_handler(line)
tokens = line.split(/\s/)
cmd = tokens.first
cmd = CMD_MAP[cmd] || cmd
return self.send(cmd.to_sym) if ONE_SHOTS.include?(cmd) && tokens.length == 1
return show_topic(cmd) if cmd =~ /^\d+$/
# If we've gotten this far, we must have args. Let's handle 'em.
arg = tokens.last
return reply(arg) if cmd == 'reply'
return edit(arg) if cmd == 'edit'
return delete(arg) if cmd == 'delete'
return mark_read(arg) if cmd == 'mark_read'
Display.say 'Unrecognized command. Type "help" for a list of available commands.'
end
def reset_display def reset_display
Display.say `tput reset`.chomp Display.say `tput reset`.chomp
end end
@ -738,9 +724,16 @@ class Interface
end end
def compose def compose
@mode = :composing Display.say 'Writing a new topic.'
@text_buffer = ''
Display.say 'Writing a new topic. Type a period on a line by itself to end message.' message_text = external_editor()
if message_text.length <= 1
Display.say 'Empty message, discarding...'
else
Message.new(message_text).save!
Display.say 'Topic saved!'
end
end end
def next def next
@ -767,18 +760,24 @@ class Interface
end end
if parent = (Corpus.find_topic_by_id(topic_id) || Corpus.find_topic_by_hash(topic_id)) if parent = (Corpus.find_topic_by_id(topic_id) || Corpus.find_topic_by_hash(topic_id))
@reply_topic = parent.hash reply_topic = parent.hash
else else
Display.say "Could not reply; unable to find a topic with ID '#{topic_id}'" Display.say "Could not reply; unable to find a topic with ID '#{topic_id}'"
return return
end end
@mode = :replying
@text_buffer = ''
title = Corpus.find_topic_by_hash(parent.hash).truncated_message(Display::TITLE_WIDTH) title = Corpus.find_topic_by_hash(parent.hash).truncated_message(Display::TITLE_WIDTH)
Display.say Display.say
Display.say "Writing a reply to topic '#{title}'" Display.say "Writing a reply to topic '#{title}'"
Display.say 'Type a period on a line by itself to end message.'
message_text = external_editor()
if message_text.length <= 1
Display.say 'Empty message, discarding...'
else
Message.new(message_text, reply_topic).save!
Display.say 'Reply saved!'
end
end end
def edit(message_id = nil) def edit(message_id = nil)
@ -803,13 +802,18 @@ class Interface
return return
end end
@mode = :editing
@old_message = message
@text_buffer = ''
title = message.truncated_message(Display::TITLE_WIDTH) title = message.truncated_message(Display::TITLE_WIDTH)
Display.say Display.say
Display.say "Editing message '#{title}'" Display.say "Editing message '#{title}'"
Display.say 'Type a period on a line by itself to end message.'
message_text = external_editor(message.message)
if message_text.length <= 1
Display.say 'Empty message, not updating...'
else
Message.edit(message_text, message)
Display.say 'Message edited!'
end
end end
def mark_read(message_id = nil) def mark_read(message_id = nil)
@ -864,71 +868,37 @@ class Interface
end end
end end
def replying_handler(line) def external_editor(preload_text = nil)
line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') tf = Tempfile.new('iris')
if line !~ /^\.$/
if @text_buffer.empty? if preload_text
@text_buffer = line tf.write(preload_text)
else tf.flush
@text_buffer = [@text_buffer, line].join("\n")
end
return
end end
if @text_buffer.length <= 1 raise "No `$EDITOR` environment variable set!" unless ENV['EDITOR'] && ENV['EDITOR'].length > 0
Display.say 'Empty message, discarding...'
else
Message.new(@text_buffer, @reply_topic).save!
Display.say 'Reply saved!'
end
@reply_topic = nil
@mode = :browsing
end
def editing_handler(line) system("#{ENV['EDITOR']} #{tf.path}")
if line !~ /^\.$/ tf.rewind
if @text_buffer.empty? message_text = tf.read
@text_buffer = line tf.unlink
else
@text_buffer = [@text_buffer, line].join("\n")
end
return
end
if @text_buffer.length <= 1 message_text
Display.say 'Empty message, not updating...'
else
Message.edit(@text_buffer, @old_message)
Display.say 'Message edited!'
end
@reply_topic = nil
@mode = :browsing
end
def composing_handler(line)
if line !~ /^\.$/
if @text_buffer.empty?
@text_buffer = line
else
@text_buffer = [@text_buffer, line].join("\n")
end
return
end
if @text_buffer.length <= 1
Display.say 'Empty message, discarding...'
else
Message.new(@text_buffer).save!
Display.say 'Topic saved!'
end
@mode = :browsing
end end
def handle(line) def handle(line)
return browsing_handler(line) if @mode == :browsing tokens = line.split(/\s/)
return composing_handler(line) if @mode == :composing cmd = tokens.first
return replying_handler(line) if @mode == :replying cmd = CMD_MAP[cmd] || cmd
return editing_handler(line) if @mode == :editing return self.send(cmd.to_sym) if ONE_SHOTS.include?(cmd) && tokens.length == 1
return show_topic(cmd) if cmd =~ /^\d+$/
# If we've gotten this far, we must have args. Let's handle 'em.
arg = tokens.last
return reply(arg) if cmd == 'reply'
return edit(arg) if cmd == 'edit'
return delete(arg) if cmd == 'delete'
return mark_read(arg) if cmd == 'mark_read'
Display.say 'Unrecognized command. Type "help" for a list of available commands.'
end end
def show_topic(num) def show_topic(num)
@ -956,15 +926,11 @@ class Interface
end end
def prompt def prompt
return 'new~> ' if @mode == :composing
return 'reply~> ' if @mode == :replying
return 'edit~> ' if @mode == :editing
"#{Config::AUTHOR}~> " "#{Config::AUTHOR}~> "
end end
def initialize(args) def initialize(args)
@history_loaded = false @history_loaded = false
@mode = :browsing
Display.say "Welcome to Iris v#{Config::VERSION}. Type 'help' for a list of commands; Ctrl-D or 'quit' to leave." Display.say "Welcome to Iris v#{Config::VERSION}. Type 'help' for a list of commands; Ctrl-D or 'quit' to leave."
unread unread