Skip to content

Instantly share code, notes, and snippets.

@sandrods
Last active April 24, 2025 15:16
Show Gist options
  • Select an option

  • Save sandrods/e238f5563d6f7ec1a5f0def1f3ed7d21 to your computer and use it in GitHub Desktop.

Select an option

Save sandrods/e238f5563d6f7ec1a5f0def1f3ed7d21 to your computer and use it in GitHub Desktop.
Focus: A Developer's Context Switcher
#!/usr/bin/env ruby
require "fileutils"
require "yaml"
FOCUS_FILE = ".focus/config.yml"
FOCUS_ROOT = ".focus"
EDITOR_COMMAND = "cursor" # Change to "code" or whatever
def list_available_sets(sets)
puts "ℹ️ Available focus sets:"
sets.keys.each { |key| puts " - #{key}" }
end
def create_example_focus_file
example = {
"invoices" => [
"app/controllers/invoices_controller.rb",
"app/models/invoice.rb",
"app/views/invoices",
"spec/models/invoice_spec.rb"
],
"auth" => [
"app/controllers/sessions_controller.rb",
"app/models/user.rb",
"app/views/sessions",
"spec/requests/login_spec.rb"
]
}
FileUtils.mkdir_p(File.dirname(FOCUS_FILE))
File.write(FOCUS_FILE, example.to_yaml)
puts "✅ Created #{FOCUS_FILE} with example sections."
end
unless File.exist?(FOCUS_FILE)
puts "⚠️ #{FOCUS_FILE} not found."
print "Would you like to create a sample one? (Y/n): "
answer = $stdin.gets.strip.downcase
if answer.empty? || answer == "y" || answer == "yes"
create_example_focus_file
system(EDITOR_COMMAND, FOCUS_FILE)
exit 0
else
puts "🚫 Aborted. Please create #{FOCUS_FILE} manually."
exit 1
end
end
begin
sets = YAML.load_file(FOCUS_FILE)
rescue Psych::SyntaxError => e
puts "❌ YAML parsing error in #{FOCUS_FILE}:\n#{e.message}"
exit 1
end
if ARGV.empty?
puts "Usage: bin/focus [section_name] [--refresh]"
list_available_sets(sets)
exit 0
end
refresh_mode = ARGV.include?("--refresh")
section = ARGV.find { |arg| !arg.start_with?("--") }
unless section
puts "❌ Please provide a section name"
list_available_sets(sets)
exit 1
end
unless sets.key?(section)
puts "❌ Section '#{section}' not found in #{FOCUS_FILE}."
list_available_sets(sets)
exit 1
end
target_dir = File.join(FOCUS_ROOT, section)
puts "🔄 #{refresh_mode ? "Refreshing" : "Creating"} symlinks in #{target_dir}/ ..."
# Only remove existing symlinks if not in refresh mode
FileUtils.rm_rf(target_dir) unless refresh_mode
sets[section].each do |relative_path|
source_path = File.expand_path(relative_path)
dest_path = File.join(target_dir, relative_path)
if File.exist?(source_path)
begin
FileUtils.mkdir_p(File.dirname(dest_path))
FileUtils.ln_s(source_path, dest_path) unless File.exist?(dest_path)
puts "✅ Linked: #{relative_path}"
rescue Errno::EEXIST
puts "ℹ️ Already exists: #{relative_path}"
end
else
puts "❌ Missing: #{relative_path}"
end
end
puts "\n📂 Focus folder ready: #{target_dir}"
puts "🚀 Opening with: #{EDITOR_COMMAND} #{target_dir}/"
system(EDITOR_COMMAND, target_dir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment