# 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 \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"}]