Class: Kotoshu::Documents::PlainTextDocument

Inherits:
Document
  • Object
show all
Defined in:
lib/kotoshu/documents/plain_text_document.rb

Overview

Plain text document implementation.

Handles plain text files with line-based navigation and correction.

Examples:

Creating a plain text document

doc = PlainTextDocument.new("Hello world\nHow are you?")
doc.text_nodes.each { |node| puts node.text }

Constant Summary

Constants inherited from Document

Document::FORMATS

Instance Attribute Summary

Attributes inherited from Document

#content, #format, #language_code

Instance Method Summary collapse

Methods inherited from Document

detect_format, detect_language_from_path, from_file, from_string, #line_count, #word_count

Constructor Details

#initialize(content, format: :text, language_code: 'en') ⇒ PlainTextDocument

Create a new plain text document.

Parameters:

  • content (String)

    The document content

  • format (Symbol) (defaults to: :text)

    Document format (must be :text)

  • language_code (String) (defaults to: 'en')

    Language code

Raises:

  • (ArgumentError)


21
22
23
24
25
26
# File 'lib/kotoshu/documents/plain_text_document.rb', line 21

def initialize(content, format: :text, language_code: 'en')
  raise ArgumentError, "Format must be :text" unless format == :text

  super(content, format: format, language_code: language_code)
  @lines = content.lines
end

Instance Method Details

#apply(corrections) ⇒ PlainTextDocument

Apply corrections and return new document.

Corrections are applied in reverse order to preserve offsets.

Parameters:

Returns:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/kotoshu/documents/plain_text_document.rb', line 117

def apply(corrections)
  return self if corrections.empty?

  # Sort by location (reverse order for offset preservation)
  sorted_corrections = corrections.sort_by { |c| c.location.line }.reverse

  new_doc = self
  corrections.each do |error|
    suggestion = error.recommended_suggestion
    new_doc = new_doc.replace_node(error.location, suggestion.word)
  end

  new_doc
end

#context_for(location, window: 5) ⇒ Models::Context

Get context around a location.

Returns lines before and after the error location.

Parameters:

  • location (Location)

    The error location (must be line/column)

  • window (Integer) (defaults to: 5)

    Number of lines before/after (default: 5)

Returns:

Raises:

  • (ArgumentError)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/kotoshu/documents/plain_text_document.rb', line 52

def context_for(location, window: 5)
  raise ArgumentError, "Location must be line/column" unless location.line_column?

  start_line = [0, location.line - window - 1].max
  end_line = [@lines.size - 1, location.line + window - 1].min

  before = @lines[start_line...(location.line - 1)].join("\n")
  current = @lines[location.line - 1]
  after = @lines[(location.line + 1)..end_line].join("\n")

  Models::Context.new(
    before: before,
    current: current,
    after: after,
    location: location,
    window: window
  )
end

#get_node(path) ⇒ String?

Get node at path (for plain text, just returns line).

Parameters:

  • path (Array)

    Node path (e.g., [:line, 5])

Returns:

  • (String, nil)

    The line content



75
76
77
78
79
80
81
82
# File 'lib/kotoshu/documents/plain_text_document.rb', line 75

def get_node(path)
  return nil unless path.is_a?(Array) && path.first == :line

  line_idx = path[1]
  return nil if line_idx < 0 || line_idx >= @lines.size

  @lines[line_idx]
end

#linesArray<String>

Get lines as array.

Returns:

  • (Array<String>)

    Lines



142
143
144
# File 'lib/kotoshu/documents/plain_text_document.rb', line 142

def lines
  @lines
end

#nameString

Document name for display.

Returns:

  • (String)

    Document name



135
136
137
# File 'lib/kotoshu/documents/plain_text_document.rb', line 135

def name
  "plain_text"
end

#replace_node(location, new_text) ⇒ PlainTextDocument

Replace text at a specific location.

For plain text, modifies a specific line.

Parameters:

  • location (Location)

    The location to replace

  • new_text (String)

    The new text

Returns:

Raises:

  • (ArgumentError)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/kotoshu/documents/plain_text_document.rb', line 91

def replace_node(location, new_text)
  raise ArgumentError, "Location must be line/column" unless location.line_column?

  new_lines = @lines.dup
  line = new_lines[location.line - 1]

  # Replace the word at the specified column
  if location.column > 0 && location.column < line.length
    before = line[0...location.column]
    after = line[(location.column + @original.length)..-1] || ''
    line = "#{before}#{new_text}#{after}"
  else
    line = new_text
  end

  new_lines[location.line - 1] = line

  PlainTextDocument.new(new_lines.join("\n"), @format, @language_code)
end

#text_nodesArray<TextNode>

Get all text nodes for spell checking.

Each line becomes a text node.

Returns:

  • (Array<TextNode>)

    Text nodes (one per line)



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/kotoshu/documents/plain_text_document.rb', line 33

def text_nodes
  @lines.each_with_index.map do |line, idx|
    # Strip leading/trailing whitespace but preserve structure
    stripped_line = line.rstrip
    next TextNode.new(
      stripped_line,
      location: Location.for_line_column(idx + 1, 0),
      node_path: [:line, idx]
    ) if stripped_line && !stripped_line.empty?
  end.compact
end