Documentation
¶
Index ¶
- Constants
- Variables
- func IsControlKey(key int) bool
- func IsPrintable(key int) bool
- func KeyName(key int) string
- func RunEditor(initialContent string, input io.Reader, output io.Writer, ...) (content string, saved bool, err error)
- func RunEditorWithMetadata(initialContent string, input io.Reader, output io.Writer, ...) (content string, saved bool, err error)
- func TranslateToWordStar(key int) int
- type CommandHandler
- func (ch *CommandHandler) HandleAbort(inputHandler *InputHandler) bool
- func (ch *CommandHandler) HandleHelp(inputHandler *InputHandler)
- func (ch *CommandHandler) HandleQuote(inputHandler *InputHandler, currentLine, currentCol int) (int, int)
- func (ch *CommandHandler) HandleSave() bool
- func (ch *CommandHandler) HandleView(inputHandler *InputHandler)
- func (ch *CommandHandler) SetQuoteData(data *QuoteData)
- func (ch *CommandHandler) ShowEscapeMenu(inputHandler *InputHandler) CommandType
- type CommandType
- type EditorContext
- type FSEditor
- func (e *FSEditor) GetBuffer() *MessageBuffer
- func (e *FSEditor) GetContent() string
- func (e *FSEditor) HandleResize(newWidth, newHeight int)
- func (e *FSEditor) IsModified() bool
- func (e *FSEditor) IsSaved() bool
- func (e *FSEditor) LoadContent(content string)
- func (e *FSEditor) Run() (string, bool, error)
- func (e *FSEditor) SetBoardName(name string)
- func (e *FSEditor) SetEditorContext(ctx EditorContext)
- func (e *FSEditor) SetMetadata(subject, recipient, fromName string, isAnon bool)
- func (e *FSEditor) SetQuoteData(data *QuoteData)
- func (e *FSEditor) SetTimezone(configTZ string)
- type InputHandler
- func (ih *InputHandler) Close()
- func (ih *InputHandler) CloseAndWait()
- func (ih *InputHandler) Read(p []byte) (int, error)
- func (ih *InputHandler) ReadKey() (int, error)
- func (ih *InputHandler) ReadKeyTranslated() (int, error)
- func (ih *InputHandler) ReadKeyWithTimeout(idleTimeout time.Duration) (int, error)
- func (ih *InputHandler) SetSessionIdleTimeout(d time.Duration)
- type MessageBuffer
- func (mb *MessageBuffer) Clear()
- func (mb *MessageBuffer) DeleteChar(lineNum, col int) bool
- func (mb *MessageBuffer) DeleteLine(lineNum int) bool
- func (mb *MessageBuffer) GetCharAt(lineNum, col int) rune
- func (mb *MessageBuffer) GetContent() string
- func (mb *MessageBuffer) GetLastChar(lineNum int) rune
- func (mb *MessageBuffer) GetLine(lineNum int) string
- func (mb *MessageBuffer) GetLineCount() int
- func (mb *MessageBuffer) GetLineLength(lineNum int) int
- func (mb *MessageBuffer) InsertChar(lineNum, col int, ch rune) bool
- func (mb *MessageBuffer) InsertLine(lineNum int) bool
- func (mb *MessageBuffer) IsLineEmpty(lineNum int) bool
- func (mb *MessageBuffer) JoinLines(lineNum int) bool
- func (mb *MessageBuffer) LoadContent(content string)
- func (mb *MessageBuffer) OverwriteChar(lineNum, col int, ch rune) bool
- func (mb *MessageBuffer) RemoveTrailingSpaces(lineNum int)
- func (mb *MessageBuffer) SetLine(lineNum int, content string)
- func (mb *MessageBuffer) SplitLine(lineNum, col int) bool
- type QuoteData
- type Screen
- func (s *Screen) ClearCache()
- func (s *Screen) ClearEOL()
- func (s *Screen) ClearScreen()
- func (s *Screen) DisplayFooter()
- func (s *Screen) DisplayHeader()
- func (s *Screen) DisplayStatusLine(insertMode bool, currentLine, totalLines int)
- func (s *Screen) FullRedraw(buffer *MessageBuffer, topLine, currentLine, currentCol int, insertMode bool)
- func (s *Screen) GetEditingStartY() int
- func (s *Screen) GetScreenLines() int
- func (s *Screen) GoXY(x, y int)
- func (s *Screen) HasFooter() bool
- func (s *Screen) LoadFooterTemplate(menuSetPath string) error
- func (s *Screen) LoadHeaderTemplate(menuSetPath, subject, recipient, fromName string, isAnon bool) error
- func (s *Screen) PromptRow() int
- func (s *Screen) RefreshLine(lineNum int, lineContent string, topLine int)
- func (s *Screen) RefreshScreen(buffer *MessageBuffer, topLine, currentLine, currentCol int, insertMode bool, ...)
- func (s *Screen) Reposition(currentLine, currentCol, topLine int)
- func (s *Screen) Resize(newWidth, newHeight int)
- func (s *Screen) ScrollDown(lines int)
- func (s *Screen) ScrollUp(lines int)
- func (s *Screen) UpdateDynamicFields(insertMode bool, currentLine, totalLines int)
- func (s *Screen) WriteDirect(text string)
- func (s *Screen) WriteDirectProcessed(text string)
- type WordWrapper
- func (ww *WordWrapper) CheckAndWrap(lineNum, col int) (int, int)
- func (ww *WordWrapper) DeleteWord(lineNum, col int) bool
- func (ww *WordWrapper) FindWordLeft(lineNum, col int) int
- func (ww *WordWrapper) FindWordRight(lineNum, col int) int
- func (ww *WordWrapper) HandleBackspace(lineNum, col int) (int, int, bool)
- func (ww *WordWrapper) HandleDelete(lineNum, col int) bool
- func (ww *WordWrapper) IsAtWordBoundary(lineNum, col int) bool
- func (ww *WordWrapper) ReformatParagraph(startLine int) int
Constants ¶
const ( // MaxLines is the maximum number of lines in a message (100 lines, 1-based indexing) MaxLines = 100 // MaxLineLength is the maximum length of a line before word wrap (79 chars) MaxLineLength = 79 )
const ( // WordStar navigation commands KeyCtrlE = 0x05 // Up KeyCtrlX = 0x18 // Down KeyCtrlS = 0x13 // Left KeyCtrlD = 0x04 // Right KeyCtrlW = 0x17 // Home (start of line) KeyCtrlP = 0x10 // End (end of line) KeyCtrlR = 0x12 // Page Up KeyCtrlC = 0x03 // Page Down // Command shortcuts (shown in footer: CTRL (A)Abort (Z)Save (Q)Quote) KeyCtrlA = 0x01 // Abort (formerly Word Left) KeyCtrlZ = 0x1A // Save KeyCtrlQ = 0x11 // Quote // Word navigation KeyCtrlF = 0x06 // Word Right // Edit commands KeyCtrlV = 0x16 // Toggle Insert/Overwrite KeyCtrlG = 0x07 // Delete character at cursor KeyCtrlT = 0x14 // Delete word KeyCtrlY = 0x19 // Delete line KeyCtrlJ = 0x0A // Join lines (also Enter/LF in some contexts) KeyCtrlN = 0x0E // Split line (new line) KeyCtrlB = 0x02 // Reformat paragraph KeyCtrlL = 0x0C // Redisplay screen // Special keys KeyEsc = 0x1B // Escape KeyEnter = 0x0D // Carriage Return KeyBackspace = 0x08 // Backspace KeyTab = 0x09 // Tab KeyDelete = 0x7F // Delete (DEL character) // Special internal codes for arrow keys (outside normal byte range) KeyArrowUp = 0x100 // Internal code for up arrow KeyArrowDown = 0x101 // Internal code for down arrow KeyArrowLeft = 0x102 // Internal code for left arrow KeyArrowRight = 0x103 // Internal code for right arrow KeyPageUp = 0x104 // Internal code for page up KeyPageDown = 0x105 // Internal code for page down KeyHome = 0x106 // Internal code for home KeyEnd = 0x107 // Internal code for end KeyInsert = 0x108 // Internal code for insert KeyDeleteKey = 0x109 // Internal code for delete key )
Special key codes for editor commands (using WordStar-style control characters)
Variables ¶
var ErrIdleTimeout = errors.New("idle timeout")
ErrIdleTimeout is returned by ReadKeyWithTimeout when no input arrives before the caller-supplied deadline. It is distinct from the internal inter-byte escape-sequence timeout so that callers can handle user-visible idle disconnects without false-positive matches on sequence parsing.
Functions ¶
func IsControlKey ¶
IsControlKey returns true if the key is a control character
func IsPrintable ¶
IsPrintable returns true if the key is a printable character
func RunEditor ¶
func RunEditor(initialContent string, input io.Reader, output io.Writer, outputMode ansi.OutputMode) (content string, saved bool, err error)
RunEditor takes initial text, the input/output streams from the SSH session, the output mode (CP437 or UTF-8), runs a full-screen editor, and returns the final text content, whether it was saved, and any error.
func RunEditorWithMetadata ¶
func RunEditorWithMetadata(initialContent string, input io.Reader, output io.Writer, outputMode ansi.OutputMode, subject, recipient, fromName string, isAnon bool, quoteFrom, quoteTitle, quoteDate, quoteTime string, quoteIsAnon bool, quoteLines []string, ih *InputHandler, ctx ...EditorContext) (content string, saved bool, err error)
RunEditorWithMetadata is an extended version that accepts message metadata. fromName is the sender display name shown in the @F@ header field: the user's handle by default, their real name when the area requires it, or the configured anonymous string when the user chose to post anonymously.
ih is an optional pre-created *InputHandler to share with the caller's reader. Pass nil to create a new one internally. Passing a shared InputHandler prevents the editor's goroutine from consuming bytes after the editor exits.
func TranslateToWordStar ¶
TranslateToWordStar translates arrow keys to WordStar equivalents
Types ¶
type CommandHandler ¶
type CommandHandler struct {
// contains filtered or unexported fields
}
CommandHandler handles special slash commands
func NewCommandHandler ¶
func NewCommandHandler(screen *Screen, buffer *MessageBuffer, menuSetPath, yesNoHi, yesNoLo, yesText, noText, abortText string) *CommandHandler
NewCommandHandler creates a new command handler
func (*CommandHandler) HandleAbort ¶
func (ch *CommandHandler) HandleAbort(inputHandler *InputHandler) bool
HandleAbort handles the Abort command (CTRL-A). Displays a lightbar Yes/No confirmation in the last footer row (PromptRow). Returns true to signal abort and exit; false restores the footer row and continues.
func (*CommandHandler) HandleHelp ¶
func (ch *CommandHandler) HandleHelp(inputHandler *InputHandler)
HandleHelp handles the /H (help) command Displays the help screen
func (*CommandHandler) HandleQuote ¶
func (ch *CommandHandler) HandleQuote(inputHandler *InputHandler, currentLine, currentCol int) (int, int)
HandleQuote handles the Quote command (CTRL-Q). Follows Pascal flow: display message inline, prompt for line range, insert quote. Prompts appear in PromptRow (last footer row); footer is restored by the caller's FullRedraw.
func (*CommandHandler) HandleSave ¶
func (ch *CommandHandler) HandleSave() bool
HandleSave handles the Save command (CTRL-Z). Returns true to signal save and exit; on false, an error is written to PromptRow.
func (*CommandHandler) HandleView ¶
func (ch *CommandHandler) HandleView(inputHandler *InputHandler)
HandleView handles the /V (view) command Displays the current message (not fully implemented)
func (*CommandHandler) SetQuoteData ¶
func (ch *CommandHandler) SetQuoteData(data *QuoteData)
SetQuoteData sets the message data to be used for the /Q quote command
func (*CommandHandler) ShowEscapeMenu ¶
func (ch *CommandHandler) ShowEscapeMenu(inputHandler *InputHandler) CommandType
ShowEscapeMenu displays a lightbar selection menu at PromptRow when Escape is pressed. Items: Save, Abort, Edit (continue), Help, Quote. Returns the selected CommandType, or CommandNone to continue editing.
type CommandType ¶
type CommandType int
CommandType represents a special editor command
const ( CommandNone CommandType = iota CommandSave // /S - Save and exit CommandAbort // /A - Abort editing CommandQuote // /Q - Quote previous message CommandHelp // /H or /? - Show help CommandView // /V - View message (not implemented in this version) )
type EditorContext ¶
type EditorContext struct {
NodeNumber int // Current node number (@K@)
NextMsgNum int // Next message number in the area (@#@)
ConfArea string // "Conference > Area" combined string (@Z@)
}
EditorContext carries optional display-only metadata for the editor header. Pass this to RunEditorWithMetadata to populate @K@ (node), @#@ (msg num), and @Z@ (conference > area) placeholders in FSEDITOR.ANS.
type FSEditor ¶
type FSEditor struct {
// contains filtered or unexported fields
}
FSEditor is the full-screen message editor
func NewFSEditor ¶
func NewFSEditor(session ssh.Session, terminal io.Writer, outputMode ansi.OutputMode, termWidth, termHeight int, menuSetPath, yesNoHi, yesNoLo, yesText, noText, abortText string, ih *InputHandler) *FSEditor
NewFSEditor creates a new full-screen editor instance. ih is an optional pre-created InputHandler to reuse (pass nil to create a new one). Passing a shared InputHandler prevents the editor's background goroutine from racing with the caller's reader for bytes after the editor exits.
func (*FSEditor) GetBuffer ¶
func (e *FSEditor) GetBuffer() *MessageBuffer
GetBuffer returns the message buffer (for testing)
func (*FSEditor) GetContent ¶
GetContent returns the editor content
func (*FSEditor) HandleResize ¶
HandleResize handles terminal resize events
func (*FSEditor) IsModified ¶
IsModified returns whether the content was modified
func (*FSEditor) LoadContent ¶
LoadContent loads initial content into the editor
func (*FSEditor) SetBoardName ¶
SetBoardName sets the BBS board name substituted into the footer @B@ placeholder.
func (*FSEditor) SetEditorContext ¶
func (e *FSEditor) SetEditorContext(ctx EditorContext)
SetEditorContext sets optional context fields displayed in the editor header (node number, next message number, conference > area name).
func (*FSEditor) SetMetadata ¶
SetMetadata sets the message metadata (subject, recipient, sender, etc.)
func (*FSEditor) SetQuoteData ¶
SetQuoteData sets message data to be used for the /Q quote command
func (*FSEditor) SetTimezone ¶
SetTimezone configures the timezone used for date/time display in the editor header.
type InputHandler ¶
type InputHandler struct {
// contains filtered or unexported fields
}
InputHandler handles keyboard input and escape sequence parsing. A background goroutine continuously reads raw bytes from the underlying reader into a buffered channel. This makes select-based timeouts reliable regardless of whether the reader supports SetReadDeadline (e.g. ssh.Session).
func NewInputHandler ¶
func NewInputHandler(input io.Reader) *InputHandler
NewInputHandler creates a new input handler. A goroutine is started to read from input; it exits when input returns an error.
func (*InputHandler) Close ¶
func (ih *InputHandler) Close()
Close stops the background read loop for handlers backed by sessions that support SetReadInterrupt. It is safe to call multiple times.
func (*InputHandler) CloseAndWait ¶
func (ih *InputHandler) CloseAndWait()
CloseAndWait stops the background goroutine and blocks until it has fully exited (including the deferred setReadInterrupt(nil) call). This eliminates the race where a door's SetReadInterrupt call is overwritten by the outgoing handler's deferred cleanup. For sessions without SetReadInterrupt support (e.g. telnet), it returns immediately after signaling close.
func (*InputHandler) Read ¶
func (ih *InputHandler) Read(p []byte) (int, error)
Read implements io.Reader. It reads exactly one byte from the incoming channel, blocking until a byte is available or the channel is closed (EOF). This allows InputHandler to be wrapped by bufio.NewReader and shared between callers (e.g. menu loops and the full-screen editor) so that the background goroutine's bytes are not lost when the editor returns.
func (*InputHandler) ReadKey ¶
func (ih *InputHandler) ReadKey() (int, error)
ReadKey reads a single key, handling escape sequences. Returns an integer code (may be > 255 for special keys).
func (*InputHandler) ReadKeyTranslated ¶
func (ih *InputHandler) ReadKeyTranslated() (int, error)
ReadKeyTranslated reads a key and translates arrow keys to WordStar commands
func (*InputHandler) ReadKeyWithTimeout ¶
func (ih *InputHandler) ReadKeyWithTimeout(idleTimeout time.Duration) (int, error)
ReadKeyWithTimeout is identical to ReadKey but waits at most idleTimeout for the very first byte. If no input arrives within that window it returns (0, ErrIdleTimeout). Inter-byte timeouts for escape-sequence parsing are unaffected. This is the extensible primitive for idle-disconnect logic.
func (*InputHandler) SetSessionIdleTimeout ¶
func (ih *InputHandler) SetSessionIdleTimeout(d time.Duration)
SetSessionIdleTimeout sets the session-level idle timeout applied to every ReadKey call. Pass 0 to disable. Thread-safe.
type MessageBuffer ¶
type MessageBuffer struct {
// contains filtered or unexported fields
}
MessageBuffer manages the text content of the message being edited
func NewMessageBuffer ¶
func NewMessageBuffer() *MessageBuffer
NewMessageBuffer creates a new message buffer
func (*MessageBuffer) DeleteChar ¶
func (mb *MessageBuffer) DeleteChar(lineNum, col int) bool
DeleteChar deletes a character at the specified position (1-based)
func (*MessageBuffer) DeleteLine ¶
func (mb *MessageBuffer) DeleteLine(lineNum int) bool
DeleteLine deletes a line at the specified position (1-based)
func (*MessageBuffer) GetCharAt ¶
func (mb *MessageBuffer) GetCharAt(lineNum, col int) rune
GetCharAt returns the character at a specific position (1-based)
func (*MessageBuffer) GetContent ¶
func (mb *MessageBuffer) GetContent() string
GetContent returns the entire buffer content as a string
func (*MessageBuffer) GetLastChar ¶
func (mb *MessageBuffer) GetLastChar(lineNum int) rune
GetLastChar returns the last character on a line
func (*MessageBuffer) GetLine ¶
func (mb *MessageBuffer) GetLine(lineNum int) string
GetLine returns the content of a line (1-based)
func (*MessageBuffer) GetLineCount ¶
func (mb *MessageBuffer) GetLineCount() int
GetLineCount returns the current number of lines
func (*MessageBuffer) GetLineLength ¶
func (mb *MessageBuffer) GetLineLength(lineNum int) int
GetLineLength returns the length of a line
func (*MessageBuffer) InsertChar ¶
func (mb *MessageBuffer) InsertChar(lineNum, col int, ch rune) bool
InsertChar inserts a character at the specified position (1-based line and col)
func (*MessageBuffer) InsertLine ¶
func (mb *MessageBuffer) InsertLine(lineNum int) bool
InsertLine inserts a new blank line at the specified position (1-based)
func (*MessageBuffer) IsLineEmpty ¶
func (mb *MessageBuffer) IsLineEmpty(lineNum int) bool
IsLineEmpty returns true if a line is empty or contains only whitespace
func (*MessageBuffer) JoinLines ¶
func (mb *MessageBuffer) JoinLines(lineNum int) bool
JoinLines joins the current line with the next line
func (*MessageBuffer) LoadContent ¶
func (mb *MessageBuffer) LoadContent(content string)
LoadContent loads initial content into the buffer
func (*MessageBuffer) OverwriteChar ¶
func (mb *MessageBuffer) OverwriteChar(lineNum, col int, ch rune) bool
OverwriteChar overwrites a character at the specified position (1-based)
func (*MessageBuffer) RemoveTrailingSpaces ¶
func (mb *MessageBuffer) RemoveTrailingSpaces(lineNum int)
RemoveTrailingSpaces removes trailing spaces from a line
func (*MessageBuffer) SetLine ¶
func (mb *MessageBuffer) SetLine(lineNum int, content string)
SetLine sets the content of a line (1-based)
func (*MessageBuffer) SplitLine ¶
func (mb *MessageBuffer) SplitLine(lineNum, col int) bool
SplitLine splits a line at the specified column (1-based) Returns true if successful
type QuoteData ¶
type QuoteData struct {
From string // Message author
Title string // Message subject/title
Date string // Message date
Time string // Message time
IsAnon bool // Anonymous flag
Lines []string // Message content lines
}
QuoteData holds message metadata for quoting
type Screen ¶
type Screen struct {
// contains filtered or unexported fields
}
Screen handles all screen rendering and ANSI control
func (*Screen) ClearCache ¶
func (s *Screen) ClearCache()
ClearCache clears the screen cache to force a full redraw on next refresh
func (*Screen) ClearScreen ¶
func (s *Screen) ClearScreen()
ClearScreen clears the entire screen and homes the cursor
func (*Screen) DisplayFooter ¶
func (s *Screen) DisplayFooter()
DisplayFooter renders the footer template at the bottom of the terminal. Must be called after ClearScreen (e.g. within FullRedraw) to repaint the footer.
func (*Screen) DisplayHeader ¶
func (s *Screen) DisplayHeader()
DisplayHeader displays the header template, then overlays dynamic row-4 fields.
func (*Screen) DisplayStatusLine ¶
DisplayStatusLine displays the status line at the bottom
func (*Screen) FullRedraw ¶
func (s *Screen) FullRedraw(buffer *MessageBuffer, topLine, currentLine, currentCol int, insertMode bool)
FullRedraw performs a complete screen redraw
func (*Screen) GetEditingStartY ¶
GetEditingStartY returns the Y position where text editing begins
func (*Screen) GetScreenLines ¶
GetScreenLines returns the number of available editing lines
func (*Screen) LoadFooterTemplate ¶
LoadFooterTemplate loads and processes the FSEDITORF.ANS footer template. The footer is always 2 rows tall and is positioned at the bottom of the screen. Screen geometry (statusLineY) is adjusted to prevent the editing area from overwriting footer rows.
func (*Screen) LoadHeaderTemplate ¶
func (s *Screen) LoadHeaderTemplate(menuSetPath, subject, recipient, fromName string, isAnon bool) error
LoadHeaderTemplate loads and processes the FSEDITOR.ANS template. fromName is the sender display name: handle, real name, or anonymous string.
func (*Screen) PromptRow ¶
PromptRow returns the terminal row used for ephemeral command prompts (abort confirmation, save notice, quote range input, etc.). With a footer this is the last terminal row (the "ViSiON/3 Edit" tagline row), which is restored by DisplayFooter after the command completes. Without a footer it falls back to statusLineY.
func (*Screen) RefreshLine ¶
RefreshLine redraws a single line if it has changed
func (*Screen) RefreshScreen ¶
func (s *Screen) RefreshScreen(buffer *MessageBuffer, topLine, currentLine, currentCol int, insertMode bool, forceStatusUpdate bool)
RefreshScreen redraws all visible lines (incremental update)
func (*Screen) Reposition ¶
Reposition moves cursor to the current editing position
func (*Screen) ScrollDown ¶
ScrollDown scrolls the display down by the specified number of lines
func (*Screen) UpdateDynamicFields ¶
UpdateDynamicFields updates dynamic fields in the status line (like Insert/Line indicators)
func (*Screen) WriteDirect ¶
WriteDirect writes directly to the terminal (for special messages)
func (*Screen) WriteDirectProcessed ¶
WriteDirectProcessed writes directly to the terminal with pipe code processing
type WordWrapper ¶
type WordWrapper struct {
// contains filtered or unexported fields
}
WordWrapper handles word wrapping and paragraph formatting
func NewWordWrapper ¶
func NewWordWrapper(buffer *MessageBuffer) *WordWrapper
NewWordWrapper creates a new word wrapper
func (*WordWrapper) CheckAndWrap ¶
func (ww *WordWrapper) CheckAndWrap(lineNum, col int) (int, int)
CheckAndWrap checks if the current line exceeds the maximum length and performs word wrapping if necessary Returns the new cursor position (line, col)
func (*WordWrapper) DeleteWord ¶
func (ww *WordWrapper) DeleteWord(lineNum, col int) bool
DeleteWord deletes the word to the right of the cursor
func (*WordWrapper) FindWordLeft ¶
func (ww *WordWrapper) FindWordLeft(lineNum, col int) int
FindWordLeft finds the start of the word to the left
func (*WordWrapper) FindWordRight ¶
func (ww *WordWrapper) FindWordRight(lineNum, col int) int
FindWordRight finds the start of the word to the right
func (*WordWrapper) HandleBackspace ¶
func (ww *WordWrapper) HandleBackspace(lineNum, col int) (int, int, bool)
HandleBackspace handles backspace at the given position May trigger line joining if at start of line Returns new cursor position (line, col)
func (*WordWrapper) HandleDelete ¶
func (ww *WordWrapper) HandleDelete(lineNum, col int) bool
HandleDelete handles delete at the given position May trigger line joining if at end of line Returns whether delete was successful
func (*WordWrapper) IsAtWordBoundary ¶
func (ww *WordWrapper) IsAtWordBoundary(lineNum, col int) bool
IsAtWordBoundary returns true if cursor is at a word boundary
func (*WordWrapper) ReformatParagraph ¶
func (ww *WordWrapper) ReformatParagraph(startLine int) int
ReformatParagraph reformats a paragraph starting at the specified line This joins lines and redistributes words to maintain proper wrapping