Search code examples
sublimetext2sublimetext3sublime-text-plugin

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

Solution

  • After seeing the updated question with an example of a full file, I went ahead and created a Sublime Text plugin with some basic options to control over sorting.

    1. Install IndentRespectfulSort from Package Control (See https://packagecontrol.io/packages/Indent%20Respectful%20Sort for instructions).
    2. Open the console by Ctrl + ` or Cmd(⌘) + `(OSX).
    3. Assuming your file is indented by 2 spaces as in the question and you would like to sort function names only, type

      view.run_command("indent_respectful_sort", {"indent": "  ", "onlyDepth" : 3})
      

      into the console and hit Enter. This will sort only the function names while respecting the rest of the structure.

    If you would like to sort with different options, you may refer to the plugin page https://github.com/mvnural/sublime-indent-respectful-sort to see more options.