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, :vim], sniff: /vim/i, url: "mvim://open?url=file://%{file_unencoded}&line=%{line}"},
  {symbols: [:rubymine, :mine], 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, :mate], 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
HTML_TEMPLATE =

Pre-built HTML template to avoid string interpolation

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url_proc) ⇒ FilePathParser

Returns a new instance of FilePathParser.



83
84
85
# File 'app/models/onlylogs/file_path_parser.rb', line 83

def initialize(url_proc)
  @url_proc = url_proc
end

Class Method Details

.cached_editor_instanceObject



68
69
70
71
72
73
74
# File 'app/models/onlylogs/file_path_parser.rb', line 68

def self.cached_editor_instance
  @cached_editor_instance ||= if ENV["ONLYLOGS_EDITOR_URL"]
    for_formatting_string(ENV["ONLYLOGS_EDITOR_URL"])
  else
    editor_from_symbol(Onlylogs.editor)
  end
end

.clear_editor_cacheObject



64
65
66
# File 'app/models/onlylogs/file_path_parser.rb', line 64

def self.clear_editor_cache
  @cached_editor_instance = nil
end

.editor_from_symbol(symbol) ⇒ Object



76
77
78
79
80
81
# File 'app/models/onlylogs/file_path_parser.rb', line 76

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

.for_formatting_string(formatting_string) ⇒ Object



47
48
49
50
51
52
53
54
55
# 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



57
58
59
# File 'app/models/onlylogs/file_path_parser.rb', line 57

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



101
102
103
# File 'app/models/onlylogs/file_path_parser.rb', line 101

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

#url(raw_path, line) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/models/onlylogs/file_path_parser.rb', line 87

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

  url_proc.call(file, line)
end