# Encoding: UTF-8

[{beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n#\n# Assignment block tidier, version 0.1.\n#\n# Copyright Chris Poirier 2006.\n# Licensed under the Academic Free License version 3.0.\n#\n# This script can be used as a command for TextMate to align all \n# of the equal signs within a block of text.  When using it with\n# TextMate, set the command input to \"Selected Text\" or \"Document\",\n# and the output to \"Replace Selected Text\".  Map it to a key \n# equivalent, and any time you want to tidy up a block, either \n# select it, or put your cursor somewhere within it; then hit the\n# key equivalent.  Voila.\n#\n# Note that this is the first version of the script, and it hasn't\n# been heavily tested.  You might encounter a bug or two. \n#\n# Per the license, use of this script is ENTIRELY at your own risk.\n# See the license for full details (they override anything I've \n# said here).\n\nlines = STDIN.readlines()\nselected_text = ENV.member?(\"TM_SELECTED_TEXT\")\n\nrelevant_line_pattern = /^[^=]+[^-+<>=!%\\/|&*^]=(?!=|~)/\ncolumn_search_pattern = /[\\t ]*=/\n\n\n#\n# If called on a selection, every assignment statement\n# is in the block.  If called on the document, we start on the \n# current line and look up and down for the start and end of the\n# block.\n\nif selected_text then\n   block_top    = 1\n   block_bottom = lines.length\nelse\n \n   #\n   # We start looking on the current line.  However, if the\n   # current line doesn't match the pattern, we may be just\n   # after or just before a block, and we should check.  If\n   # neither, we are done.\n\n   start_on      = ENV[\"TM_LINE_NUMBER\"].to_i\n   block_top     = lines.length + 1\n   block_bottom  = 0\n   search_top    = 1\n   search_bottom = lines.length\n   search_failed = false\n\n   if lines[start_on - 1] !~ relevant_line_pattern then\n      if lines[start_on - 2] =~ relevant_line_pattern then\n         search_bottom = start_on = start_on - 1\n      elsif lines[start_on] =~ relevant_line_pattern then\n         search_top = start_on = start_on\n      else\n         search_failed = true\n      end \n   end\n\n   #\n   # Now with the search boundaries set, start looking for\n   # the block top and bottom.\n   \n   unless search_failed\n      start_on.downto(search_top) do |number|\n         if lines[number-1] =~ relevant_line_pattern then\n            block_top = number\n         else\n            break\n         end\n      end\n      \n      start_on.upto(search_bottom) do |number|\n         if lines[number-1] =~ relevant_line_pattern then\n            block_bottom = number\n         else\n            break\n         end\n      end\n   end\nend\n\n\n#\n# Now, iterate over the block and find the best column number\n# for the = sign.  The pattern will tell us the position of the\n# first bit of whitespace before the equal sign.  We put the\n# equals sign to the right of the furthest-right one.  Note that\n# we cannot assume every line in the block is relevant.\n\nbest_column = 0\nblock_top.upto(block_bottom) do |number|\n   line = lines[number - 1]\n   if line =~ relevant_line_pattern then\n      m = column_search_pattern.match(line)\n      best_column = m.begin(0) if m.begin(0) > best_column\n   end\nend\n\n   \n#\n# Reformat the block.  Again, we cannot assume all lines in the \n# block are relevant.\n\nblock_top.upto(block_bottom) do |number|\n   if lines[number-1] =~ relevant_line_pattern then\n      before, after = lines[number-1].split(/[\\t ]*=[\\t ]*/, 2)\n      lines[number-1] = [before.ljust(best_column), after].join(after[0,1] == '>' ? \" =\" : \" = \")\n   end\nend\n\n\n#\n# Output the replacement text\n\nlines.each do |line|\n   puts line\nend\n",
  input: "selection",
  keyEquivalent: "~@]",
  name: "Align Assignments",
  output: "replaceSelectedText",
  uuid: "FCBE2215-19CA-470A-8D92-BB0D00491D62"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\n# by James Edward Gray II <james (at) grayproductions.net>\n\n# \n# To override the operation of this commond for your language add a Preferences\n# bundle item that defines the following valiables as appropriate for your\n# language:\n# \n#   TM_COMMENT_START - the character string that starts comments, e.g. /*\n#   TM_COMMENT_END   - the character string that ends comments (if appropriate),\n#                      e.g. */\n#   TM_COMMENT_MODE  - the type of comment to use - either 'line' or 'block'\n# \n\nrequire \"\#{ENV[\"TM_SUPPORT_PATH\"]}/lib/escape\"\n\ndef out(*args)\n  print( *args.map do |arg|\n    escaped = e_sn(arg)\n    $selected ? escaped.gsub(\"}\", \"\\\\}\") : escaped.sub(\"\\0\", \"${0}\")\n  end )\nend\n\n# find all available comment variables\nvar_suffixes = [\"\"]\n2.upto(1.0/0.0) do |n|\n  if ENV.include? \"TM_COMMENT_START_\#{n}\"\n    var_suffixes << \"_\#{n}\"\n  else\n    break\n  end\nend\n\ntext    = STDIN.read\ndefault = nil  # the comment we will insert, if none are removed\n\n# maintain selection\nif text == ENV[\"TM_SELECTED_TEXT\"]\n  $selected = true\n  print \"${0:\"\n  at_exit { print \"}\" }\nelse\n  $selected = false\nend\n\n# try a removal for each comment...\nvar_suffixes.each do |suffix|\n  # build comment\n  com = { :start     => ENV[\"TM_COMMENT_START\#{suffix}\"] || \"# \",\n          :end       => ENV[\"TM_COMMENT_END\#{suffix}\"]   || \"\",\n          :mode      => ENV[\"TM_COMMENT_MODE\#{suffix}\"]  ||\n                        (ENV[\"TM_COMMENT_END\#{suffix}\"] ? \"block\" : \"line\"),\n          :no_indent => ENV[\"TM_COMMENT_DISABLE_INDENT\#{suffix}\"] }\n  \n  com[:esc_start], com[:esc_end] = [com[:start], com[:end]].map do |str|\n    str.gsub(/[\\\\|()\\[\\].?*+{}^$]/, '\\\\\\\\\\&').\n        gsub(/\\A\\s+|\\s+\\z/, '(?:\\&)?')\n  end\n  \n  # save the first one as our insertion default\n  default = com if default.nil?\n  \n  # try a removal\n  case com[:mode]\n  when \"line\"  # line by line comment\n    if text !~ /\\A[\\t ]+\\z/ &&\n       text.send(text.respond_to?(:lines) ? :lines : :to_s).\n            map { |l| !!(l =~ /\\A\\s*(\#{com[:esc_start]}|$)/) }.uniq == [true]\n      if $selected\n        out text.gsub( /^(\\s*)\#{com[:esc_start]}(.*?)\#{com[:esc_end]}(\\s*)$/,\n                       '\\1\\2\\3' )\n        exit\n      else\n        r = text.sub( /^(\\s*)\#{com[:esc_start]}(.*?)\#{com[:esc_end]}(\\s*)$/,\n                      '\\1\\2\\3' )\n        i = ENV[\"TM_LINE_INDEX\"].to_i\n        i = i > text.index(/\#{com[:esc_start]}/)            ?\n            [[0, i - com[:start].length].max, r.length].min :\n            [i, r.length].min\n        r[i, 0] = \"\\0\"\n        out r\n        exit\n      end\n    end\n  when \"block\" # block comment\n    regex = /\\A(\\s*)\#{com[:esc_start]}(.*?)\#{com[:esc_end]}(\\s*)\\z/m\n    if text =~ regex\n      if $selected\n        out text.sub(regex, '\\1\\2\\3')\n        exit\n      else\n        r = text.sub(regex, '\\1\\2\\3')\n        i = ENV[\"TM_LINE_INDEX\"].to_i\n        i = i > text.index(/\#{com[:esc_start]}/)            ?\n            [[0, i - com[:start].length].max, r.length].min :\n            [i, r.length].min\n        r[i, 0] = \"\\0\"\n        out r\n        exit\n      end\n    end\n  end\nend\n\n# none of our removals worked, so preform an insert (minding indent setting)\ntext[ENV[\"TM_LINE_INDEX\"].to_i, 0] = \"\\0\" unless $selected or text.empty?\ncase default[:mode]\nwhen \"line\"  # apply comment line by line\n  if text.empty?\n    out \"\#{default[:start]}\\0\#{default[:end]}\"\n  elsif default[:no_indent]\n    out text.gsub(/^.*$/, \"\#{default[:start]}\\\\&\#{default[:end]}\")\n  elsif text =~ /\\A([\\t ]*)\\0([\\t ]*)\\z/\n    out text.gsub(/^.*$/, \"\#{$1}\#{default[:start]}\#{$2}\#{default[:end]}\")\n  else\n    indent = text.scan(/^[\\t \\0]*(?=\\S)/).\n                  min { |a, b| a.length <=> b.length } || \"\"\n    text.send(text.respond_to?(:lines) ? :lines : :to_s).map do |line|\n      if line =~ /^(\#{indent})(.*)$(\\n?)/ then\n        out $1 + default[:start] + $2 + default[:end] + $3\n      elsif line =~ /^(.*)$(\\n?)/ then\n        out indent + default[:start] + $1 + default[:end] + $2\n      end\n    end\n  end\nwhen \"block\" # apply comment around selection\n  if text.empty?\n    out default[:start]\n    print \"${0}\"\n    out default[:end]\n  elsif text =~ /\\A([\\t ]*)\\0([\\t ]*)\\z/\n    out $1, default[:start]\n    print \"${0}\"\n    out $2, default[:end]\n  elsif default[:no_indent]\n    out default[:start], text, default[:end]\n  else\n    lines = text.to_a\n    if lines.empty?\n      out default[:start], default[:end]\n    else\n      lines[-1].sub!(/^(.*)$/, \"\\\\1\#{default[:end]}\")\n      out lines.shift.sub(/^([\\s\\0]*)(.*)$/, \"\\\\1\#{default[:start]}\\\\2\")\n      out(*lines) unless lines.empty?\n    end\n  end\nend\n",
  fallbackInput: "line",
  input: "selection",
  keyEquivalent: "@/",
  name: "Comment Line / Selection",
  output: "insertAsSnippet",
  uuid: "73EAE95D-A09C-4FC2-B4E3-42505678B57E"},
 {beforeRunningCommand: "saveActiveFile",
  command: 
   "#!/usr/bin/env ruby\n\n# This is a little more convoluted than it needs to be\n# just to ensure that we can do an OK job on really long\n# files.  Frankly, it's probably all for nothing given\n# that we likely have plenty of memory, and that Ruby will\n# probably go an cache a whole chunk of the file somewhere in\n# the IO pipeline anyway - but we like to make the effort.\n\nspacing = nil\nlines = Array.new()\nline = $stdin.gets()\nwhile(line != nil)\n\tlines << line\n\tif(line =~ /^\\t/)  # mixed tabs with spaces, use TM's tab setting\n\t\tspacing = ENV['TM_TAB_SIZE']\n\t\tbreak\n\telsif(line =~ /^[ ]+\\S/)\n\t\tspacing = line[/^([ ]+)\\S/, 1].length\n\t\tbreak\n\tend\n\n\tline = $stdin.gets()\nend\n\nif(spacing != nil)\n\tfp = IO.popen(\"cat \\\"\#{ENV['TM_FILEPATH']}\\\" | unexpand -t \#{spacing}\", \"r\")\n\tline = fp.gets()\n\twhile(line != nil)\n\t\tprint line\n\t\tline = fp.gets\n\tend\nelse\n\tlines.each() { |line|\n\t\tprint line\n\t}\n\n\tline = $stdin.gets()\n\twhile(line != nil)\n\t\tprint line\n\t\tline = $stdin.gets()\n\tend\nend\n",
  input: "document",
  keyEquivalent: "^@T",
  name: "Convert Spaces to Tabs (Estimating Indent)",
  output: "replaceDocument",
  uuid: "0526D870-BE98-4931-8DBF-FDD3D405BB1B"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby -wKU\nrequire ENV['TM_SUPPORT_PATH'] + '/lib/escape.rb'\nrequire ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes.rb'\n\ndef find_markers\n  10.times do |n|\n    start = ENV[\"TM_COMMENT_START\#{\"_\#{n}\" if n > 0}\"].to_s.strip\n    stop  = ENV[\"TM_COMMENT_END\#{\"_\#{n}\"   if n > 0}\"].to_s.strip\n    return start, stop if not start.empty? and not stop.empty?\n  end\n  TextMate.exit_show_tool_tip \"No block comment markers found for this language.\"\nend\n\nstart, stop = find_markers\ninput = STDIN.read.to_s\n\nif input =~ /\\n/\n  start << \"\\n\"\n  stop  << \"\\n\"\nend\n\nSTDOUT << e_sn(start) << (input.empty? ? \"\\n\\t$0\\n\" : e_sn(input)) << e_sn(stop)\n",
  fallbackInput: "none",
  input: "selection",
  keyEquivalent: "~@/",
  name: "Insert Block Comment",
  output: "insertAsSnippet",
  uuid: "83560C23-63E2-4920-8E26-7EAC5FE86B2F"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\n#\n# Notes:\n#\n# '(c)' is legally ambiguous. '©' is not ambiguous, but may cause problems for some compilers.\n# The copyright symbol is redundant if the word 'Copyright' is present, so it's safe to omit it\n# entirely.\n#\n\nfile_placeholder = '${1:«file»}'\nproject_placeholder = '${2:«project»}'\n\ntm_filename\t\t= ENV['TM_FILENAME']\t\t\t|| file_placeholder\ntm_project_dir\t= ENV['TM_PROJECT_DIRECTORY']\t|| ''\ncomment_start \t= ENV['TM_COMMENT_START']\t\t|| ''\ncomment_end\t\t= ENV['TM_COMMENT_END'] \t\t|| ''\ncopyright_holder\t= ENV['TM_ORGANIZATION_NAME']\n\nproject = case tm_project_dir\nwhen /.*\\/(.*)/\n\tproject = Regexp.last_match(1)\nelse\n\tproject_placeholder\nend\n\n# use line comments?\nline_comment\t= ''\nindent\t\t= ' ' * (comment_start.length + 1)\n\nif comment_end.empty?\n\tline_comment = comment_start\n\tcomment_start = ''\n\tcomment_end = ''\n\tindent = ' '\nend\n\nusername\t= ENV['TM_FULLNAME']\ndate\t\t= `date +%Y-%m-%d`.chomp\n\n# Default to username if no organization name\ncopyright_holder ||= username\n\nprint %Q{\#{line_comment}\#{comment_start}\n\#{line_comment}\#{indent}\#{tm_filename}\n\#{line_comment}\#{indent}\#{project}\n\#{line_comment}\#{indent}\n\#{line_comment}\#{indent}Created by \#{username} on \#{date}.\n\#{line_comment}\#{indent}Copyright \#{`date +%Y`.chomp} \#{copyright_holder}. All rights reserved.\n\#{line_comment}\#{comment_end}\n$0}\n",
  input: "none",
  name: "Insert Comment Header",
  output: "insertAsSnippet",
  tabTrigger: "head",
  uuid: "3050DE46-2337-476A-B733-8063B61ECB63"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\n$LOAD_PATH << \"\#{ENV[\"TM_SUPPORT_PATH\"]}/lib\"\nrequire \"escape\"\nrequire \"exit_codes\"\n\nctext = STDIN.read\nif ctext =~ /^\\s*(.[^\\s\\w\\\\]*\\s*)/\n  cstring = $1\nelse\n  TextMate.exit_show_tool_tip(\"Unable to determine comment character.\")\nend\n\nflags = %Q{-p \"\#{cstring}\"}\nflags += \" --retabify\" unless ENV[\"TM_SOFT_TABS\"] == \"YES\"\n\ncommand = \"ruby \#{e_sh(ENV[\"TM_BUNDLE_SUPPORT\"])}/bin/rubywrap.rb \#{flags}\"\ntext    = open(\"| \#{command}\", \"r+\") do |wrapper|\n  wrapper << ctext\n  wrapper.close_write\n  wrapper.read\nend\n\nprint e_sn(text)\n",
  fallbackInput: "scope",
  input: "selection",
  keyEquivalent: "^q",
  name: "Reformat Comment",
  output: "insertAsSnippet",
  scope: "comment.line",
  uuid: "F20AD964-3C68-4940-91B1-8A99B8E2A375"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\nprint case str = STDIN.read\n  when /\\A\"(.*)\"\\z/m; \"'\" + $1 + \"'\"\n  when /\\A'(.*)'\\z/m; '\"' + $1 + '\"'\n  else str\nend\n",
  fallbackInput: "scope",
  input: "selection",
  keyEquivalent: "^\"",
  name: "Toggle Single / Double String Quotes",
  output: "replaceSelectedText",
  scope: "string.quoted.single, string.quoted.double",
  uuid: "70A0BC8E-98E0-4D14-B004-7ACA9162B496"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\nrequire ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes'\n\n# Test Cases\n# \n# AFooBar -> a_foo_bar -> aFooBar -> AFooBar\n# URLString -> url_string -> urlString -> UrlString\n# TestURLString -> test_url_string -> testUrlString -> TestUrlString\n# test -> Test -> test\n# test_URL_STRING -> testUrlString -> TestUrlString -> test_url_string\n\n\n# HotFlamingCats -> hot_flaming_cats\ndef pascalcase_to_snakecase(word)\n\tword.gsub(/\\B([A-Z])(?=[a-z0-9])|([a-z0-9])([A-Z])/, '\\2_\\+').downcase\nend\n\n# hot_flaming_cats -> hotFlamingCats\ndef snakecase_to_camelcase(word)\n  word.gsub(/_([^_]+)/) { $1.capitalize }\nend\n\n# hotFlamingCats -> HotFlamingCats\ndef camelcase_to_pascalcase(word)\n\tword.gsub(/^\\w{1}/) {|c| c.upcase}\nend\n\nword = $stdin.gets\n\nTextMate.exit_discard if word.nil?\n\nis_pascal = word.match(/^[A-Z]{1}/) ? true : false\nis_snake = word.match(/_/) ? true : false\n\nif is_pascal then\n\tprint pascalcase_to_snakecase(word)\nelsif is_snake then\n\tprint snakecase_to_camelcase(word)\nelse\n\tprint camelcase_to_pascalcase(word) \nend\n",
  fallbackInput: "word",
  input: "selection",
  keyEquivalent: "^_",
  name: "Toggle camelCase / snake_case / PascalCase",
  output: "replaceSelectedText",
  scope: "source",
  uuid: "6065BB2D-242A-4C3D-B523-6F560D65AC11"},
 {beforeRunningCommand: "nop",
  command: 
   "#!/usr/bin/env ruby\n\ntermchar = ENV['TM_LINE_TERMINATOR'] || \";\"\n\n# short for escape_snippet - escapes special snippet characters in str\ndef es(str)\n\tstr.to_s.gsub(/([$`\\\\])/, \"\\\\\\\\\\\\1\")\nend\n\nprint es($stdin.read()[/^(.*?);*\\s*$/, 1]) + \"\#{es(termchar)}$0\"",
  fallbackInput: "line",
  input: "selection",
  keyEquivalent: "~@\n",
  name: "and Insert Terminator",
  output: "insertAsSnippet",
  scope: "source",
  uuid: "CA1849DD-D6EC-415D-8788-DD93BE027F6D"}]
