Module: RuVim::Gh::Link

Defined in:
lib/ruvim/gh/link.rb

Defined Under Namespace

Modules: HandlerMethods

Class Method Summary collapse

Class Method Details

.build_url(base_url, ref, relative_path, line_start, line_end = nil) ⇒ Object

Build a GitHub blob URL.



25
26
27
28
29
30
31
32
# File 'lib/ruvim/gh/link.rb', line 25

def build_url(base_url, ref, relative_path, line_start, line_end = nil)
  fragment = if line_end && line_end != line_start
               "#L#{line_start}-L#{line_end}"
             else
               "#L#{line_start}"
             end
  "#{base_url}/blob/#{ref}/#{relative_path}#{fragment}"
end

.file_differs_from_remote?(root, remote_name, branch, file_path) ⇒ Boolean

Check if a file differs from the remote tracking branch.

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
# File 'lib/ruvim/gh/link.rb', line 74

def file_differs_from_remote?(root, remote_name, branch, file_path)
  remote_ref = "#{remote_name}/#{branch}"
  diff_out, _, status = Open3.capture3("git", "diff", remote_ref, "--", file_path, chdir: root)
  # If the remote ref doesn't exist or diff fails, consider it as differing
  return true unless status.success?

  !diff_out.empty?
end

.find_github_remote(root, remote_name = nil) ⇒ Object

Find a GitHub remote. If remote_name is given, use that specific remote. Otherwise, scan all remotes (preferring "origin", then "upstream", then others). Returns [remote_name, base_url] or [nil, nil].



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ruvim/gh/link.rb', line 43

def find_github_remote(root, remote_name = nil)
  if remote_name
    url, _, status = Open3.capture3("git", "remote", "get-url", remote_name, chdir: root)
    return [nil, nil] unless status.success?

    base = github_url_from_remote(url.strip)
    return base ? [remote_name, base] : [nil, nil]
  end

  remotes_out, _, status = Open3.capture3("git", "remote", chdir: root)
  return [nil, nil] unless status.success?

  remotes = remotes_out.lines(chomp: true)
  # Prefer origin, then upstream, then others
  ordered = []
  ordered << "origin" if remotes.include?("origin")
  ordered << "upstream" if remotes.include?("upstream")
  remotes.each { |r| ordered << r unless ordered.include?(r) }

  ordered.each do |name|
    url, _, st = Open3.capture3("git", "remote", "get-url", name, chdir: root)
    next unless st.success?

    base = github_url_from_remote(url.strip)
    return [name, base] if base
  end

  [nil, nil]
end

.github_url_from_remote(remote_url) ⇒ Object

Parse a git remote URL and return the GitHub HTTPS base URL. Returns nil if the remote is not a GitHub URL.



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/ruvim/gh/link.rb', line 12

def github_url_from_remote(remote_url)
  url = remote_url.to_s.strip
  return nil if url.empty?

  case url
  when %r{\Agit@github\.com:(.+?)(?:\.git)?\z}
    "https://github.com/#{$1}"
  when %r{\Ahttps://github\.com/(.+?)(?:\.git)?\z}
    "https://github.com/#{$1}"
  end
end

.osc52_copy_sequence(text) ⇒ Object

Generate OSC 52 escape sequence for clipboard copy.



35
36
37
38
# File 'lib/ruvim/gh/link.rb', line 35

def osc52_copy_sequence(text)
  encoded = [text].pack("m0")
  "\e]52;c;#{encoded}\a"
end

.pr_search_url(base_url, branch) ⇒ Object

Build a GitHub PR search URL for a branch.



113
114
115
# File 'lib/ruvim/gh/link.rb', line 113

def pr_search_url(base_url, branch)
  "#{base_url}/pulls?q=head:#{branch}"
end

.resolve(file_path, line_start, line_end = nil, remote_name: nil) ⇒ Object

Resolve GitHub link for a file path at given line(s). Returns [url, warning, error_message].



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/ruvim/gh/link.rb', line 85

def resolve(file_path, line_start, line_end = nil, remote_name: nil)
  root, err = RuVim::Git.repo_root(file_path)
  return [nil, nil, err] unless root

  found_remote, base_url = find_github_remote(root, remote_name)
  unless base_url
    msg = remote_name ? "Remote '#{remote_name}' is not a GitHub remote" : "No GitHub remote found"
    return [nil, nil, msg]
  end

  branch, _, status = Open3.capture3("git", "rev-parse", "--abbrev-ref", "HEAD", chdir: root)
  unless status.success?
    return [nil, nil, "Cannot determine branch"]
  end
  branch = branch.strip

  relative_path = file_path.sub(%r{\A#{Regexp.escape(root)}/?}, "")
  url = build_url(base_url, branch, relative_path, line_start, line_end)

  warning = nil
  if file_differs_from_remote?(root, found_remote, branch, file_path)
    warning = "(remote may differ)"
  end

  [url, warning, nil]
end

.resolve_pr(file_path) ⇒ Object

Resolve GitHub PR URL for the current repo. Returns [url, error_message].



119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ruvim/gh/link.rb', line 119

def resolve_pr(file_path)
  root, err = RuVim::Git.repo_root(file_path)
  return [nil, err] unless root

  _, base_url = find_github_remote(root)
  return [nil, "No GitHub remote found"] unless base_url

  branch, _, status = Open3.capture3("git", "rev-parse", "--abbrev-ref", "HEAD", chdir: root)
  return [nil, "Cannot determine branch"] unless status.success?

  [pr_search_url(base_url, branch.strip), nil]
end