Sublime Forum

Problem Report: Convert Case > Title Case not working correctly on selected lines

#1

I am finding that applying the command to convert text to title case is not working correctly when multiple lines of text are selected (it works correctly when only a single line is selected).

As an example, assume the following four lines are selected:

real PROBLEM
Law suites
reputation
external certification of the development processes
APT – hackers and nation states

Executing Convert Case > Title Case yields the following incorrect result:

Real Problem
law Suites
reputation
external Certification Of The Development Processes
apt – Hackers And Nation States

The first line is correctly capitalized, but the remaining lines all have their first words incorrectly converted to all lower case (though the remaining words on those lines are correctly capitalized).

0 Likes

#2

The implementation of this command is in Default/transform.py:

class Transformer(sublime_plugin.TextCommand):
    def run(self, edit):
        view = self.view
        for s in view.sel():
            if s.empty():
                s = view.word(s)

            txt = self.transformer(view.substr(s))
            view.replace(edit, s, txt)

class TitleCaseCommand(Transformer):
    @staticmethod
    def transformer(s):
        return string.capwords(s, " ")

As seen here, the command operates by extracting each block of selected text and then running string.capwords() on it. The documentation for this method says:

If the optional second argument sep is absent or None , runs of whitespace characters are replaced by a single space and leading and trailing whitespace are removed, otherwise sep is used to split and join the words.

Since the call here is passing in the second argument as a space, the underlying Python interpreter splits the output into words using spaces, which is the basis of the problem; the newlines that separate the lines of text are not being considered as word separators.

That results in something like this given your example:

>>> view.substr(view.sel()[0]).split(" ")
['real', 'PROBLEM\nLaw', 'suites\nreputation\nexternal', 
'certification', 'of', 'the', 'development', 'processes\nAPT', '–', 
'hackers', 'and', 'nation', 'states']

Given that, Law is made lower case because it’s actually part of a larger word, reputation and external are similarly not individual words, and so on.

One way around that would be to split the selection into lines before you execute the command; in that case every line would be considered in turn and it would work as expected.

Alternately, you could use an override to replace the code for TitleCaseCommand to use the title() method instead:

class TitleCaseCommand(Transformer):
    @staticmethod
    def transformer(s):
        return s.title()

It may be worth logging a bug on the issue tracker for this; there’s not any clear indication that I can see that this should only be applied to single lines and not blocks of text. It also does the wrong thing if the text contains physical tabs (even if you split the selection into lines).

1 Like

#3

Thank you. This worked for me though, not being familiar with overrides, I did have to Google some. OverrideAudit package helped me quickly locate TitleCaseCommand and edit it.

By the way, I’m on Build 4107. I’m not quite sure this is truly a “bug” or not, but this is still TitleCaseCommand's default behavior.

0 Likes