Last active
April 24, 2025 15:16
-
-
Save sandrods/e238f5563d6f7ec1a5f0def1f3ed7d21 to your computer and use it in GitHub Desktop.
Focus: A Developer's Context Switcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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