Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sublime Text Sorting with Respect to Indentation

I'm looking for a Sublime Text plugin or any kind of program that can sort alphabetically but respect the indentation.

For example,

beatsByUserPath: (userId) ->
  "/api/beats/by_user/#{userId}"
sendMassMessagePath: ->
  "/api/send_mass_message"
sendMessagePath: (userId) ->
  "/api/send_message/#{userId}"
feedbackCreatePath: ->
  "/api/feedbacks"

Would be sorted by the function names. Using the default sort in Sublime Text leads to:

  "/api/beats/by_user/#{userId}"
  "/api/feedbacks"
  "/api/send_mass_message"
  "/api/send_message/#{userId}"
beatsByUserPath: (userId) ->
feedbackCreatePath: ->
sendMassMessagePath: ->
sendMessagePath: (userId) ->

Here is the full file that I would like to sort.

RouteHelper =
  EXTERNAL:
    soundcloudConvertPath: (url) ->
      url = encodeURIComponent(url)
      "http://streampocket.com/?stream=#{url}"
    youtubeConvertPath: (url) ->
      url = encodeURIComponent(url)
      "http://www.video2mp3.net/loading.php?url=#{url}"
  UTIL:
    imageProxy: (url) ->
      url = encodeURIComponent(url)
      "/image-proxy/#{url}"
  API:
    beatsReportPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/report"
    beatsTrackDownloadPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/track_download"
    beatSetDownloadPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/set_download_url"
    beatsToggleVisibilityPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/toggle_visibility"
    beatsToggleRecordingPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/toggle_recording"
    beatsDisownPath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/disown"
    beatsEditNotePath: (param) ->
      beatId = param
      beatId = param.id if typeof param is 'object' && param.id
      "/api/beats/#{beatId}/edit_note"
    beatsByUserPath: (userId) ->
      "/api/beats/by_user/#{userId}"
    discussPath: ->
      "/api/discuss"
    sendMassMessagePath: ->
      "/api/send_mass_message"
    sendMessagePath: (userId) ->
      "/api/send_message/#{userId}"
    feedbackCreatePath: ->
      "/api/feedbacks"
    feedbacksForRapPath: (arg) ->
      rapId = if typeof rap is 'object' then arg.id else arg
      "/api/feedbacks/feedback_for/#{rapId}"
    followersPath: (userId) ->
      "/api/followers/#{userId}"
    followingPath: (userId) ->
      "/api/following/#{userId}"
    followPath: (userId) ->
      "/api/follow/#{userId}"
    unfollowPath: (userId) ->
      "/api/unfollow/#{userId}"
    propsPath: ->
      "/api/props"
    userBattlesPath_deprecated: (userId) ->
      "/api/battles/for_user/#{userId}"
    battlesLeaderboardPath: ->
      "/api/battles/leaderboard"
    battlesUsersWhoVotedForPath: (opts) ->
      throw Error('RouteHelper: Expected ID and WHICH') if !opts.id || !opts.which
      "/api/battles/#{opts.id}/users_who_voted_for/#{opts.which}"
    rapProppersPath: (rapId) ->
      "/api/raps/#{rapId}/proppers"
    rapUntagPath: (rapId) ->
      "/api/raps/#{rapId}/untag"
    rapShowPath: (param) ->
      if typeof param is 'object'
        rapId = param.id
      else rapId = param
      "/api/raps/#{rapId}/show_v2"
    userPinPath: ->
      "/api/users/pin"
    userBattlesPath: (userId) ->
      "/api/users/#{userId}/battles"
    userBeatsPath: (userId) ->
      "/api/users/#{userId}/beats"
    userRapsPath: (userId) ->
      "/api/users/#{userId}/raps_v2"
    userSetColorsPath: (userId) ->
      "/api/users/#{userId}/set_colors"
    userShowPath: (userId) ->
      "/api/users/#{userId}"
    usersWhoGaveProps: (userId) ->
      "/api/users/#{userId}/users_who_gave_props"
    userUnreadNotifCount: (userId) ->
      "/api/users/#{userId}/unread_notif_count"
    userRecordNetegoPath: ->
      "/api/users/record_net_ego"
  albumShowPath: (param) ->
    param = param.slug if _.isObject(param)
    "/albums/#{param}"
  blueprintShowPathFromRap: (rap) ->
    "/blueprints/#{rap.blueprint_id}"
  battleDestroyPath: (battle) ->
    "/battles/#{battle.id}"
  battlesPath: ->
    "/battles"
  battleNewPath: ->
    "/battles/new"
  battleShowPath: (battle) ->
    "/battles/#{battle.id}"
  beatNewPath: ->
    "/beats/new"
  beatShowPath: (beat) ->
    if typeof beat is 'number'
      "/beats/#{beat}"
    else if typeof beat is 'object'
      if beat.slug
        "/beats/#{beat.slug}"
      else
        "/beats/#{beat.id}"
  beatTagShowPath: (beatTag) ->
    "#{beatTag.slug}/instrumentals"
  beatsSearchQueryPath: ->
    "/beats/search_query"
  beatsRecentSearchesPath: ->
    "/beats/recent_searches"
  cypherJudgeVotePath: ->
    "/cyphers/judge-vote"
  cypherJudgeShowPath: ->
    "/cyphers/judge-show"
  cypherSubmitPath: ->
    "/cyphers/submit"
  dashboardPath: ->
    "/dashboard"
  defaultRapThumbnailPath: ->
    "/images/default_rap.png"
  rhymePath: ->
    "/rhyme"
  contextPath: ->
    "/context"
  searchLyricsPath: ->
    "/rap/search_lyrics"
  editorSavePath: ->
    "/editor/save"
  editorPath: (param) ->
    param = param.id if typeof param is 'object'
    if param
      "/editor/#{param}"
    else
      "/editor"
  onRapSaveDialogPath: (rapId) ->
    "/rap/#{rapId}/on_save_dialog"
  lyricSyncSavePath: ->
    "/lyric-sync/save"
  lyricSyncDestroyPath: ->
    "/lyric-sync/destroy"
  notificationsPath: ->
    "/notifications"
  rapEditPath: (rap) ->
    "/editor/#{rap.id}"
  rapShowPath: (rap) ->
    "/rap/#{rap.id}"
  rapsForCypher: (cypherId) ->
    "/cyphers/#{cypherId}/submissions"
  isSubscribedPath: (listId) ->
    "/is_subscribed/#{listId}"
  subscribeToPath: (listId) ->
    "/subscribe_to/#{listId}"
  userShowPath: (username) ->
    "/users/#{username}"
  userNotificationSettingPath: ->
    "/users/notification_setting"

@RouteHelper = RouteHelper
like image 997
Overload119 Avatar asked Jan 08 '23 13:01

Overload119


1 Answers

I'm not aware of a generic solution since the definition of a block (for sorting purposes) is highly dependent on the context.

For the specific case you have posted however, it can be easily accomplished by a simple macro with the following steps:

  1. Merge each block into a single line (replace each occurrence of ->\n with ->)
  2. Sort single lines
  3. Unmerge each block from a single line back to original indented form (replace each occurrence of -> with ->\n)

The only problem is, Sublime doesn't record find & replace commands in a macro. Instead, we need to install RegReplace package which provides find & replace commands that can be recorded in a macro. (See http://facelessuser.github.io/RegReplace/installation/ for installation instructions)

Once RegReplace is installed, just put the following two files under Packages/User/ in your data directory (What is the full path to the Packages folder for Sublime text 2 on Mac OS Lion)

You can now run smart_sort by selecting Tools -> Macros -> smart_sort from the top menu.

Disclaimer: If you have more than 1 indented line per function, you need to adjust the regex definitions accordingly.

smart_sort.sublime-macro (the macro)

[
    {
        "args":
        {
            "replacements":
            [
                "merge_block_into_a_line"
            ]
        },
        "command": "reg_replace"
    },
    {
        "args":
        {
            "case_sensitive": false
        },
        "command": "sort_lines"
    },
    {
        "args":
        {
            "replacements":
            [
                "restore_block"
            ]
        },
        "command": "reg_replace"
    }
]

reg_replace.sublime-settings (reg_replace definitions)

{
    "replacements": {
        "merge_block_into_a_line": {
            "find": "->\\n",
            "replace": "->",
            "greedy": true,
            "case": true
        },
        "restore_block": {
            "find": "->",
            "replace": "->\\n",
            "greedy": true,
            "case": true
        }
    }
}
like image 194
Mustafa Avatar answered Jan 13 '23 14:01

Mustafa