Class: Onlylogs::FilePathParser

Inherits:
Object
  • Object
show all
Defined in:
app/models/onlylogs/file_path_parser.rb

Constant Summary collapse

KNOWN_EDITORS =
[
  { symbols: [ :atom ], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
  { symbols: [ :emacs, :emacsclient ], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
  { symbols: [ :idea ], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
  { symbols: [ :macvim, :mvim ], sniff: /vim/i, url: "mvim://open?url=file://%{file_unencoded}&line=%{line}" },
  { symbols: [ :rubymine ], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
  { symbols: [ :sublime, :subl, :st ], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
  { symbols: [ :textmate, :txmt, :tm ], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
  { symbols: [ :vscode, :code ], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
  { symbols: [ :vscodium, :codium ], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" }
].freeze
FILE_PATH_PATTERN =

Pre-compiled regex for better performance

%r{
  (?<![a-zA-Z0-9_/])  # Negative lookbehind - not preceded by word chars or /
  (?:\./)?             # Optional relative path indicator
  (?:/[a-zA-Z0-9_\-\.\s]+)+  # File path with allowed characters
  (?:\.rb|\.js|\.ts|\.tsx|\.jsx|\.py|\.java|\.go|\.rs|\.php|\.html|\.erb|\.haml|\.slim|\.css|\.scss|\.sass|\.less|\.xml|\.json|\.yml|\.yaml|\.md|\.txt|\.log)  # File extensions
  (?::\d+)?            # Optional line number
  (?![a-zA-Z0-9_/])    # Negative lookahead - not followed by word chars or /
}x.freeze
HTML_TEMPLATE =

Pre-built HTML template to avoid string interpolation

'<a href="%{url}" class="file-link">%{match}</a>'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url_proc) ⇒ FilePathParser

Returns a new instance of FilePathParser.



73
74
75
# File 'app/models/onlylogs/file_path_parser.rb', line 73

def initialize(url_proc)
  @url_proc = url_proc
end

Class Method Details

.cached_editor_instanceObject



60
61
62
63
# File 'app/models/onlylogs/file_path_parser.rb', line 60

def self.cached_editor_instance
  return @cached_editor_instance if @cached_editor_instance      
  @cached_editor_instance = editor_from_symbol(Onlylogs.editor)      
end

.editor_from_symbol(symbol) ⇒ Object



66
67
68
69
70
71
# File 'app/models/onlylogs/file_path_parser.rb', line 66

def self.editor_from_symbol(symbol)
  KNOWN_EDITORS.each do |preset|
    return for_formatting_string(preset[:url]) if preset[:symbols].include?(symbol)
  end
  editor_from_symbol(:vscode)
end

.extract_file_path(match) ⇒ Object



107
108
109
110
# File 'app/models/onlylogs/file_path_parser.rb', line 107

def self.extract_file_path(match)
  # Remove line number if present
  match.sub(/:\d+$/, "")
end

.extract_line_number(match) ⇒ Object



112
113
114
115
116
# File 'app/models/onlylogs/file_path_parser.rb', line 112

def self.extract_line_number(match)
  # Extract line number or default to 1
  line_match = match.match(/:(\d+)$/)
  line_match ? line_match[1].to_i : 1
end

.for_formatting_string(formatting_string) ⇒ Object



47
48
49
50
51
# File 'app/models/onlylogs/file_path_parser.rb', line 47

def self.for_formatting_string(formatting_string)
  new proc { |file, line|
    formatting_string % { file: URI.encode_www_form_component(file), file_unencoded: file, line: line }
  }
end

.for_proc(url_proc) ⇒ Object



53
54
55
# File 'app/models/onlylogs/file_path_parser.rb', line 53

def self.for_proc(url_proc)
  new url_proc
end

.parse(string) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/models/onlylogs/file_path_parser.rb', line 33

def self.parse(string)
  return string if string.blank?

  # Early return if no file paths present
  return string unless string.match?(FILE_PATH_PATTERN)

  string.gsub(FILE_PATH_PATTERN) do |match|
    file_path = extract_file_path(match)
    line_number = extract_line_number(match)
    url = cached_editor_instance.url(file_path, line_number)
    HTML_TEMPLATE % { url: url, match: match }
  end
end

Instance Method Details

#schemeObject



91
92
93
# File 'app/models/onlylogs/file_path_parser.rb', line 91

def scheme
  url("/fake", 42).sub(/:.*/, ":")
end

#url(raw_path, line) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/models/onlylogs/file_path_parser.rb', line 77

def url(raw_path, line)
  if virtual_path && raw_path.start_with?(virtual_path)
    if host_path
      file = raw_path.sub(%r{\A#{virtual_path}}, host_path)
    else
      file = raw_path.sub(%r{\A#{virtual_path}/}, "")
    end
  else
    file = raw_path
  end

  url_proc.call(file, line)
end