canopus 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f145122cb1995d72f9ddcf886fc40d2d00c60351b6d7a227ce69011c2ca7f61
4
- data.tar.gz: 52b865cfbbda7a3e991748305282db47ce0f7f7903e50c763142defab18a0b7e
3
+ metadata.gz: 7542ff6c8bf489ddfdb978f292d32778cc450b57d64035d94ef67797901b1545
4
+ data.tar.gz: 2a7f330905efe963d94d303c953f4d1b4ae8da51a0b409720b6c1cfbccf837a6
5
5
  SHA512:
6
- metadata.gz: 50e3e24430e992f3961e2838444ce5f8c6ab8337c75ebc504f863554f219736212b46a140d89208f223c6316a8d754860de598b70e69881bf65601196cdcbd55
7
- data.tar.gz: 7ac119f37e6947ccebae40e63d6eb54bb243bc9ff149049ad02e623c4f3d210da45999ec2a3ee520c30cb87a924c8c0189a30e3333a9c39cd2e35ef14031d9bb
6
+ metadata.gz: d62037a03bb3753cddd8551d88d33f59760500f6c9680b2ae4cb284b26a11de43c1c17ea9f9e437b890e722494b83702f7666d61df76d99045d6242e8cab852e
7
+ data.tar.gz: ec60287bf355093ace58c7d24fb0805e37a207d457bbce3eae09087d03bdaa4748742d37d4e98570095bb52f55ffa01c1b78aecb600ae4699966d8101f383471
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 — 2026-09-14
4
+
5
+ - Use the public `Thuban::IgnoreMatcher` and remove Canopus's duplicate implementation.
6
+
3
7
  ## 0.2.0 — 2026-09-12
4
8
 
5
9
  - Read repositories through Thuban and keep text comparison in Porrima data objects.
@@ -0,0 +1,5 @@
1
+ # Dependency Release Log
2
+
3
+ | Date | Repository | Version | Canopus follow-up | Reason |
4
+ | --- | --- | --- | --- | --- |
5
+ | 2026-09-14 | thuban | 0.2.0 | 2026-09-14 | Public `IgnoreMatcher` API |
@@ -3,6 +3,7 @@
3
3
  require "set"
4
4
  require "fileutils"
5
5
  require "tempfile"
6
+ require "thuban"
6
7
 
7
8
  module Canopus
8
9
  class Project
@@ -26,7 +27,7 @@ module Canopus
26
27
  include_symlinks: include_symlinks, include_directories: include_directories, extensions: extensions, max_size: max_size) unless block_given?
27
28
  extensions = extensions&.map { |extension| extension.start_with?(".") ? extension : ".#{extension}" }&.to_set
28
29
  visited = Set.new
29
- base_rules = IgnoreMatcher.new
30
+ base_rules = Thuban::IgnoreMatcher.new
30
31
  exclude = File.join(root, ".git", "info", "exclude")
31
32
  base_rules = base_rules.add(File.read(exclude), base: "") if File.file?(exclude)
32
33
  walk = lambda do |directory, rules|
@@ -72,7 +73,7 @@ module Canopus
72
73
 
73
74
  def ignored?(relative, directory: File.directory?(path(relative)))
74
75
  pieces = relative.sub(%r{\A\./}, "").split("/")
75
- rules = IgnoreMatcher.new
76
+ rules = Thuban::IgnoreMatcher.new
76
77
  base = ""
77
78
  exclude = File.join(root, ".git", "info", "exclude")
78
79
  rules = rules.add(File.read(exclude), base: "") if File.file?(exclude)
@@ -122,6 +123,5 @@ module Canopus
122
123
  end
123
124
  end
124
125
 
125
- require_relative "project/ignore_matcher"
126
126
  require_relative "project/search"
127
127
  require_relative "project/watcher"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canopus
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/sig/services.rbs CHANGED
@@ -28,18 +28,6 @@ module Canopus
28
28
  def initialize: (Project project) -> void
29
29
  def call: (String | Regexp pattern, ?workers: Integer, ?max_size: Integer?, ?extensions: Array[String]?, ?limit: Integer?, ?case_sensitive: bool, ?cancelled: ^() -> bool, ?paths: Array[String]?) ?{ (Match) -> void } -> Array[Match]
30
30
  end
31
- class IgnoreMatcher
32
- class Rule < Struct[untyped]
33
- attr_accessor base: String
34
- attr_accessor expression: Regexp
35
- attr_accessor negated: bool
36
- attr_accessor directory: bool
37
- def self.new: (base: String, expression: Regexp, negated: bool, directory: bool) -> instance
38
- end
39
- def initialize: (?Array[Rule] rules) -> void
40
- def add: (String source, ?base: String) -> instance
41
- def ignored?: (String path, ?directory: bool) -> bool
42
- end
43
31
  class Watcher
44
32
  class Event < Struct[untyped]
45
33
  attr_accessor type: :created | :modified | :deleted
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canopus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-09-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: alhena
@@ -128,14 +127,14 @@ dependencies:
128
127
  requirements:
129
128
  - - "~>"
130
129
  - !ruby/object:Gem::Version
131
- version: 0.1.0
130
+ version: 0.2.0
132
131
  type: :runtime
133
132
  prerelease: false
134
133
  version_requirements: !ruby/object:Gem::Requirement
135
134
  requirements:
136
135
  - - "~>"
137
136
  - !ruby/object:Gem::Version
138
- version: 0.1.0
137
+ version: 0.2.0
139
138
  - !ruby/object:Gem::Dependency
140
139
  name: unicode-display_width
141
140
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +163,6 @@ dependencies:
164
163
  - - "~>"
165
164
  - !ruby/object:Gem::Version
166
165
  version: 0.1.0
167
- description:
168
166
  email:
169
167
  - t.yudai92@gmail.com
170
168
  executables:
@@ -189,6 +187,7 @@ files:
189
187
  - docs/distribution.md
190
188
  - docs/lsp.md
191
189
  - docs/performance.md
190
+ - docs/release-log.md
192
191
  - docs/snippets.md
193
192
  - docs/vim.md
194
193
  - docs/workspace_edits.md
@@ -246,7 +245,6 @@ files:
246
245
  - lib/canopus/plugins/permission_denied.rb
247
246
  - lib/canopus/plugins/registry.rb
248
247
  - lib/canopus/project.rb
249
- - lib/canopus/project/ignore_matcher.rb
250
248
  - lib/canopus/project/search.rb
251
249
  - lib/canopus/project/search_worker.rb
252
250
  - lib/canopus/project/search_worker/cancelled.rb
@@ -317,7 +315,6 @@ metadata:
317
315
  changelog_uri: https://github.com/noxdea/canopus/blob/main/CHANGELOG.md
318
316
  allowed_push_host: https://rubygems.org
319
317
  rubygems_mfa_required: 'true'
320
- post_install_message:
321
318
  rdoc_options: []
322
319
  require_paths:
323
320
  - lib
@@ -332,8 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
332
329
  - !ruby/object:Gem::Version
333
330
  version: '0'
334
331
  requirements: []
335
- rubygems_version: 3.3.27
336
- signing_key:
332
+ rubygems_version: 3.6.9
337
333
  specification_version: 4
338
334
  summary: A pure Ruby text editor with persistent buffers and language tools
339
335
  test_files: []
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Canopus::Project::IgnoreMatcher
4
- Rule = Struct.new(:base, :expression, :negated, :directory, keyword_init: true)
5
-
6
- def initialize(rules = [])
7
- @rules = rules.freeze
8
- end
9
-
10
- def add(source, base: "")
11
- rules = source.lines.filter_map do |line|
12
- line = line.delete_suffix("\n").delete_suffix("\r")
13
- # Only unescaped trailing spaces are insignificant.
14
- line = line.sub(/(?<!\\)(?:\\\\)*\K +\z/, "")
15
- next if line.empty? || line.start_with?("#")
16
- negated = line.start_with?("!")
17
- line = line[1..] if negated
18
- directory = line.end_with?("/")
19
- line = line.delete_suffix("/") if directory
20
- anchored = line.start_with?("/") || line.include?("/")
21
- line = line.delete_prefix("/")
22
- next if line.empty?
23
- expression = Regexp.new((anchored ? "\\A" : "(?:\\A|/)") + glob(line) + "\\z")
24
- Rule.new(base: base.delete_suffix("/"), expression: expression, negated: negated, directory: directory)
25
- rescue RegexpError
26
- nil
27
- end
28
- self.class.new(@rules + rules)
29
- end
30
-
31
- # Ancestors must be checked by the walker: excluded parents cannot be
32
- # resurrected by a child's negation, exactly as Git's pruning requires.
33
- def ignored?(path, directory: false)
34
- ignored = false
35
- @rules.each do |rule|
36
- next if rule.directory && !directory
37
- next unless rule.base.empty? || path.start_with?(rule.base + "/")
38
- local = rule.base.empty? ? path : path[(rule.base.length + 1)..]
39
- ignored = !rule.negated if rule.expression.match?(local)
40
- end
41
- ignored
42
- end
43
-
44
- private
45
-
46
- def glob(pattern)
47
- result = +""
48
- index = 0
49
- while index < pattern.length
50
- char = pattern[index]
51
- case char
52
- when "\\"
53
- index += 1
54
- result << Regexp.escape(pattern[index] || "\\")
55
- when "*"
56
- finish = index
57
- finish += 1 while pattern[finish + 1] == "*"
58
- if finish > index && (index.zero? || pattern[index - 1] == "/") && (finish == pattern.length - 1 || pattern[finish + 1] == "/")
59
- if pattern[finish + 1] == "/"
60
- result << "(?:[^/]+/)*"
61
- finish += 1
62
- else
63
- result << ".*"
64
- end
65
- else
66
- result << "[^/]*"
67
- end
68
- index = finish
69
- when "?"
70
- result << "[^/]"
71
- when "["
72
- cursor = index + 1
73
- cursor += 1 if ["!", "^"].include?(pattern[cursor])
74
- cursor += 1 if pattern[cursor] == "]"
75
- finish = nil
76
- while cursor < pattern.length
77
- if pattern[cursor, 2] == "[:" && (ending = pattern.index(":]", cursor + 2))
78
- cursor = ending + 2
79
- next
80
- end
81
- if pattern[cursor] == "]"
82
- finish = cursor
83
- break
84
- end
85
- cursor += pattern[cursor] == "\\" ? 2 : 1
86
- end
87
- if finish
88
- content = pattern[(index + 1)...finish].sub(/\A!/, "^")
89
- content = content.gsub(/(?<!\\)(.)-(.)/) { Regexp.last_match(1).ord > Regexp.last_match(2).ord ? Regexp.last_match(1) : Regexp.last_match(0) }
90
- result << "(?!/)[#{content}]"
91
- index = finish
92
- else
93
- result << "\\["
94
- end
95
- else
96
- result << Regexp.escape(char)
97
- end
98
- index += 1
99
- end
100
- result
101
- rescue RegexpError
102
- Regexp.escape(pattern)
103
- end
104
- end