-
# frozen_string_literal: true
-
-
1
require "zeitwerk"
-
-
1
Zeitwerk::Loader.new.then do |loader|
-
1
loader.inflector.inflect "ascii_doc" => "ASCIIDoc", "cli" => "CLI"
-
1
loader.tag = File.basename __FILE__, ".rb"
-
1
loader.push_dir __dir__
-
1
loader.setup
-
end
-
-
# Main namespace.
-
1
module SublimeTextKit
-
1
def self.loader registry = Zeitwerk::Registry
-
4
@loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
-
end
-
end
-
# frozen_string_literal: true
-
-
1
Gem::Specification.new do |spec|
-
1
spec.name = "sublime_text_kit"
-
1
spec.version = "17.4.0"
-
1
spec.authors = ["Brooke Kuhlmann"]
-
1
spec.email = ["brooke@alchemists.io"]
-
1
spec.homepage = "https://alchemists.io/projects/sublime_text_kit"
-
1
spec.summary = "A command line interface for managing Sublime Text metadata."
-
1
spec.license = "Hippocratic-2.1"
-
-
1
spec.metadata = {
-
"bug_tracker_uri" => "https://github.com/bkuhlmann/sublime_text_kit/issues",
-
"changelog_uri" => "https://alchemists.io/projects/sublime_text_kit/versions",
-
"homepage_uri" => "https://alchemists.io/projects/sublime_text_kit",
-
"funding_uri" => "https://github.com/sponsors/bkuhlmann",
-
"label" => "Sublime Text Kit",
-
"rubygems_mfa_required" => "true",
-
"source_code_uri" => "https://github.com/bkuhlmann/sublime_text_kit"
-
}
-
-
1
spec.signing_key = Gem.default_key_path
-
1
spec.cert_chain = [Gem.default_cert_path]
-
-
1
spec.required_ruby_version = ">= 3.3", "<= 3.4"
-
1
spec.add_dependency "cogger", "~> 0.26"
-
1
spec.add_dependency "containable", "~> 0.2"
-
1
spec.add_dependency "dry-monads", "~> 1.6"
-
1
spec.add_dependency "dry-schema", "~> 1.13"
-
1
spec.add_dependency "etcher", "~> 2.1"
-
1
spec.add_dependency "infusible", "~> 3.11"
-
1
spec.add_dependency "refinements", "~> 12.9"
-
1
spec.add_dependency "runcom", "~> 11.5"
-
1
spec.add_dependency "sod", "~> 0.17"
-
1
spec.add_dependency "spek", "~> 3.0"
-
1
spec.add_dependency "zeitwerk", "~> 2.7"
-
-
1
spec.bindir = "exe"
-
1
spec.executables << "sublime_text_kit"
-
1
spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
-
1
spec.files = Dir["*.gemspec", "lib/**/*"]
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
1
module Metadata
-
# Creates project metadata.
-
1
class Create < Sod::Action
-
1
include Import[:settings, :logger]
-
-
1
using Refinements::Pathname
-
-
1
description "Create metadata."
-
-
1
on %w[-c --create]
-
-
1
def initialize(handler: SublimeTextKit::Metadata::Handler, **)
-
12
super(**)
-
12
@handler = handler
-
end
-
-
1
def call(*)
-
3
logger.info "Creating metadata in #{metadata_dir}..."
-
3
process_projects
-
3
logger.info "Metadata created."
-
end
-
-
1
private
-
-
1
attr_reader :handler
-
-
1
def process_projects
-
3
settings.project_dirs.each do |directory|
-
9
handler.with_project(directory, metadata_dir).create
-
9
handler.with_workspace(directory, metadata_dir).create
-
end
-
end
-
-
1
def metadata_dir = Pathname(settings.metadata_dir).expand_path
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
1
module Metadata
-
# Deletes project metadata.
-
1
class Delete < Sod::Action
-
1
include Import[:settings, :logger]
-
-
1
using Refinements::Pathname
-
-
1
description "Delete metadata."
-
-
1
on %w[-d --delete]
-
-
1
def initialize(handler: SublimeTextKit::Metadata::Handler, **)
-
12
super(**)
-
12
@handler = handler
-
end
-
-
1
def call(*)
-
3
logger.info "Deleting metadata in #{metadata_dir}..."
-
3
process_projects
-
3
logger.info "Metadata deleted."
-
end
-
-
1
private
-
-
1
attr_reader :handler
-
-
1
def process_projects
-
3
settings.project_dirs.each do |directory|
-
9
handler.with_project(directory, metadata_dir).delete
-
9
handler.with_workspace(directory, metadata_dir).delete
-
end
-
end
-
-
1
def metadata_dir = Pathname(settings.metadata_dir).expand_path
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
1
module Metadata
-
# Recreates project metadata.
-
1
class Recreate < Sod::Action
-
1
include Import[:settings, :logger]
-
-
1
using Refinements::Pathname
-
-
1
description "Recreate metadata."
-
-
1
on %w[-r --recreate]
-
-
1
def initialize(handler: SublimeTextKit::Metadata::Handler, **)
-
12
super(**)
-
12
@handler = handler
-
end
-
-
1
def call(*)
-
3
logger.info "Recreating metadata in #{metadata_dir}..."
-
3
process_projects
-
3
logger.info "Metadata recreated."
-
end
-
-
1
private
-
-
1
attr_reader :handler
-
-
1
def process_projects
-
3
settings.project_dirs.each do |directory|
-
9
handler.with_project(directory, metadata_dir).recreate
-
9
handler.with_workspace(directory, metadata_dir).recreate
-
end
-
end
-
-
1
def metadata_dir = Pathname(settings.metadata_dir).expand_path
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
# Handles session action.
-
1
class Session < Sod::Action
-
1
include Import[:logger]
-
-
1
description "Rebuild session metadata."
-
-
1
on %w[-S --session]
-
-
1
def initialize(rebuilder: Sessions::Rebuilder.new, **)
-
12
super(**)
-
12
@rebuilder = rebuilder
-
end
-
-
1
def call(*)
-
3
rebuilder.call
-
3
logger.info "Session rebuilt."
-
end
-
-
1
private
-
-
1
attr_reader :rebuilder
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
# Handles snippets action.
-
1
class Snippets < Sod::Action
-
1
include Import[:settings, :logger]
-
-
1
description "View snippets."
-
-
1
on %w[-s --snippets], argument: "[FORMAT]", allow: %w[markdown ascii_doc]
-
-
15
default { Container[:settings].snippets_format }
-
-
1
def initialize(printer: SublimeTextKit::Snippets::Printer.new, **)
-
14
super(**)
-
14
@printer = printer
-
end
-
-
1
def call kind = default
-
6
when: 3
case kind
-
3
when: 2
when "ascii_doc" then printer.call "*"
-
2
else: 1
when "markdown" then printer.call "-"
-
2
else logger.error { "Invalid snippet format: #{kind}. Use ascii_doc or markdown." }
-
end
-
end
-
-
1
private
-
-
1
attr_reader :printer
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
1
module Actions
-
# Handles update action.
-
1
class Update < Sod::Action
-
1
include Import[:settings, :logger]
-
-
1
description "Update project and session metadata based on current settings."
-
-
1
on %w[-u --update]
-
-
1
def initialize(
-
metadata: SublimeTextKit::Metadata::Handler,
-
session: Sessions::Rebuilder.new,
-
**
-
)
-
13
super(**)
-
13
@metadata = metadata
-
13
@session = session
-
end
-
-
1
def call(*)
-
4
logger.info "Updating metadata and session..."
-
4
create_metadata
-
4
session.call
-
8
logger.info { "Metadata and session updated." }
-
end
-
-
1
private
-
-
1
attr_reader :metadata, :session
-
-
1
def create_metadata
-
4
settings.project_dirs.each do |directory|
-
12
metadata.with_project(directory, metadata_dir).create
-
12
metadata.with_workspace(directory, metadata_dir).create
-
end
-
end
-
-
1
def metadata_dir = Pathname(settings.metadata_dir).expand_path
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "sod"
-
-
1
module SublimeTextKit
-
1
module CLI
-
# The main Command Line Interface (CLI) object.
-
1
class Shell
-
1
include Import[:defaults_path, :xdg_config, :specification]
-
-
1
def initialize(context: Sod::Context, dsl: Sod, **)
-
10
super(**)
-
10
@context = context
-
10
@dsl = dsl
-
end
-
-
1
def call(...) = cli.call(...)
-
-
1
private
-
-
1
attr_reader :context, :dsl
-
-
1
def cli
-
10
context = build_context
-
-
10
dsl.new :sublime_text_kit, banner: specification.banner do
-
10
on(Sod::Prefabs::Commands::Config, context:)
-
-
10
on "metadata", "Manage project metadata." do
-
10
on Actions::Metadata::Create
-
10
on Actions::Metadata::Delete
-
10
on Actions::Metadata::Recreate
-
end
-
-
10
on Actions::Session
-
10
on Actions::Snippets
-
10
on Actions::Update
-
10
on(Sod::Prefabs::Actions::Version, context:)
-
10
on Sod::Prefabs::Actions::Help, self
-
end
-
end
-
-
1
def build_context
-
10
context[defaults_path:, xdg_config:, version_label: specification.labeled_version]
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "dry/schema"
-
1
require "etcher"
-
-
1
Dry::Schema.load_extensions :monads
-
-
1
module SublimeTextKit
-
1
module Configuration
-
1
Contract = Dry::Schema.Params do
-
1
optional(:project_roots).filled :array
-
1
optional(:metadata_dir).filled Etcher::Types::Pathname
-
1
required(:snippets_format).filled :string
-
1
required(:session_path).filled Etcher::Types::Pathname
-
1
required(:user_dir).filled Etcher::Types::Pathname
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
-
1
module SublimeTextKit
-
1
module Configuration
-
# Models the settings.
-
1
Model = Struct.new :project_roots, :metadata_dir, :snippets_format, :session_path, :user_dir do
-
1
using Refinements::Pathname
-
-
1
def project_dirs
-
32
Array(project_roots).map { |path| Pathname(path).expand_path }
-
.flat_map(&:directories)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "infusible"
-
-
1
module SublimeTextKit
-
1
Import = Infusible[Container]
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
-
1
module SublimeTextKit
-
1
module Metadata
-
# Handles the creation, deletion, and recreation of metadata.
-
1
class Handler
-
1
using Refinements::Pathname
-
-
1
def self.with_project project_dir, metadata_dir
-
40
new "sublime-project",
-
serializer: Serializers::Project.new(Pathway[project_dir:, metadata_dir:])
-
end
-
-
1
def self.with_workspace project_dir, metadata_dir
-
40
new "sublime-workspace",
-
serializer: Serializers::Workspace.new(Pathway[project_dir:, metadata_dir:])
-
end
-
-
1
def initialize extension, serializer:
-
91
@extension = extension
-
91
@serializer = serializer
-
end
-
-
72
then: 2
else: 69
def create = path.exist? ? path : path.write(JSON.dump(serializer.to_h))
-
-
46
then: 3
else: 42
def delete = path.exist? ? path.delete : path
-
-
1
def recreate = delete && create
-
-
1
private
-
-
1
attr_reader :extension, :serializer
-
-
1
def path = serializer.pathway.metadata_file(extension)
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module SublimeTextKit
-
1
module Metadata
-
# Defines metadata pathways.
-
1
Pathway = Struct.new :project_dir, :metadata_dir, keyword_init: true do
-
1
using Refinements::Pathname
-
-
1
def initialize *arguments
-
98
super
-
294
each_pair { |key, value| self[key] = Pathname(value).expand_path }
-
end
-
-
1
def project_name = project_dir.basename
-
-
1
def metadata_file(extension) = metadata_dir.join("#{project_name}.#{extension}")
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module SublimeTextKit
-
1
module Metadata
-
1
module Serializers
-
# Serializes project metadata.
-
1
class Project
-
1
attr_reader :pathway
-
-
1
def initialize pathway
-
53
@pathway = pathway
-
end
-
-
1
def to_h
-
{
-
39
folders: [
-
{path: pathway.project_dir.to_s}
-
]
-
}
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module SublimeTextKit
-
1
module Metadata
-
1
module Serializers
-
# Serializes workspace metadata.
-
1
class Workspace
-
1
attr_reader :pathway
-
-
1
def initialize pathway
-
42
@pathway = pathway
-
end
-
-
1
def to_h
-
{
-
32
expanded_folders: [pathway.project_dir.to_s],
-
select_project: {
-
selected_items: [
-
[pathway.project_name.to_s, pathway.metadata_file("sublime-project").to_s]
-
]
-
}
-
}
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "json"
-
1
require "refinements/pathname"
-
-
1
module SublimeTextKit
-
1
module Sessions
-
# Manages the rebuilding of session information.
-
1
class Rebuilder
-
1
include Import[:settings]
-
-
1
using Refinements::Pathname
-
-
1
def call
-
6
session = read
-
-
6
else: 3
then: 3
return unless session.dig "workspaces", "recent_workspaces"
-
-
3
Pathname(metadata_dir).expand_path
-
.files("*.sublime-workspace")
-
.then do |workspaces|
-
3
session["workspaces"]["recent_workspaces"] = workspaces
-
3
write session
-
end
-
end
-
-
1
private
-
-
7
then: 4
else: 2
def read = source_path.exist? ? JSON(source_path.read) : {}
-
-
4
def write(json) = JSON.dump(json).then { |content| source_path.write content }
-
-
1
def metadata_dir = settings.metadata_dir
-
-
1
def source_path = settings.session_path
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "refinements/pathname"
-
-
1
module SublimeTextKit
-
1
module Snippets
-
# Collects and loads all snippets into memory for further processing.
-
1
class Collector
-
1
include Import[:settings]
-
-
1
using Refinements::Pathname
-
-
1
def initialize(reader: Reader.new, **)
-
20
super(**)
-
20
@reader = reader
-
end
-
-
1
def call
-
11
settings.user_dir
-
.files("*.sublime-snippet")
-
27
.map { |path| reader.call path }
-
.sort_by(&:description)
-
end
-
-
1
private
-
-
1
attr_reader :reader
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module SublimeTextKit
-
1
module Snippets
-
1
KEY_MAP = {
-
"content" => :content,
-
"tabTrigger" => :trigger,
-
"description" => :description,
-
"scope" => :scope
-
}.freeze
-
-
# Defines a snippet record.
-
1
Model = Struct.new(*KEY_MAP.values, keyword_init: true) do
-
1
def self.for document, key_map: KEY_MAP
-
31
root = document.root
-
-
31
else: 30
then: 1
return new unless root
-
-
30
root.elements
-
116
.reduce({}) { |attributes, element| attributes.merge element.name => element.text }
-
.transform_keys(key_map)
-
30
.then { |attributes| new(**attributes) }
-
end
-
-
1
def initialize *arguments
-
41
super
-
41
freeze
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module SublimeTextKit
-
1
module Snippets
-
# Prints snippets as a list.
-
1
class Printer
-
1
include Import[:io]
-
-
1
def initialize(collector: Collector.new, **)
-
17
super(**)
-
17
@collector = collector
-
end
-
-
1
def call bullet
-
8
collector.call.each do |snippet|
-
21
io.puts "#{bullet} #{snippet.description} - `#{snippet.trigger}`"
-
end
-
end
-
-
1
private
-
-
1
attr_reader :collector
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "rexml/document"
-
-
1
module SublimeTextKit
-
1
module Snippets
-
# Reads snippet and loads record into memory.
-
1
class Reader
-
1
def initialize model: Model, document: REXML::Document
-
22
@model = model
-
22
@document = document
-
end
-
-
30
then: 28
else: 1
def call(path) = path.exist? ? model.for(document.new(path.read)) : model.new
-
-
1
private
-
-
1
attr_reader :model, :document
-
end
-
end
-
end