Page 1 of 1

using characterCase attribute

Posted: 2021-02-15 13:18:53
by B.Otter
Greetings,

I am new to Nisus Writer Pro and the macro language. I'd like to write a general purpose "Toggle Case" macro that could be applicable to the Unicode range, changing the uppercase character at the caret to lowercase and vice versa. I have a working version for the ASCII range but wonder if there's a simple solution for the entire range of Unicode?

I've had no luck with the attribute "characterCase" as in, (with a selection of a single character):

$attrs = TextSelection.active.displayTypingAttributes.characterCase

Is there a form of usage or a context in which "characterCase" is ever nonZero?

Thanks,
Brad

Re: using characterCase attribute

Posted: 2021-02-16 11:21:25
by martin
Hello Brad, welcome to using Nisus Writer and its macros!
B.Otter wrote: 2021-02-15 13:18:53 I'd like to write a general purpose "Toggle Case" macro that could be applicable to the Unicode range, changing the uppercase character at the caret to lowercase and vice versa.
Perhaps you're writing this macro as a learning exercise. But if not I just want to point out we have a command for this via the menu Edit > Transform Text > To Toggled Case.
I've had no luck with the attribute "characterCase" as in, (with a selection of a single character):

$attrs = TextSelection.active.displayTypingAttributes.characterCase

Is there a form of usage or a context in which "characterCase" is ever nonZero?
The value of this display attribute (formatting) depends on the state of the menu Format > Letter Case. It does not tell you anything about the underlying text's character codes; it tells you if the user has applied any display transformations. The latter works like other kinds of formatting (eg: bold font) and is enforced dynamically by Nisus Writer's display processing. You might read my blog post on letter case conversions for more details.

What is probably going to be more helpful to you is something like the \p{Upper} or \p{Lower} search patterns that are part of regular expression's Unicode support. Writing Nisus Writer macro code to manually handle all the possible letters in Unicode would be quite a task!

I hope that helps. Please let me know if you have any more questions.

Re: using characterCase attribute

Posted: 2021-02-16 11:41:00
by B.Otter
Martin, thank you, totally clear and helpful.

I had overlooked the "Edit > Transform Text > To Toggled Case" — a perfect fit for my editing needs. Interestingly, it looks as though the transforms to UPPERCASE and lowercase seem to work with diacriticals such as ō and Ō, however, the "To Toggled Case" leaves each of these characters in their original states.

Agreed, a complete table for unicode case conversions would be onerous.

The usage for the attribute "characterCase" is also clear and consistent—when I take the macro manual as written. Smile.

In any case, all helpful.

Thanks.

Re: using characterCase attribute

Posted: 2021-02-17 09:06:03
by phspaelti
Since the "To UPPERCASE" and "to lowercase" work, as you point out, you can leverage them to create a togglecase macro as appended.

Re: using characterCase attribute

Posted: 2021-02-17 09:57:48
by B.Otter
phspaelti wrote: 2021-02-17 09:06:03 Since the "To UPPERCASE" and "to lowercase" work, as you point out, you can leverage them to create a togglecase macro as appended.
Philip, thank you, learned from your code.

Brad

Re: using characterCase attribute

Posted: 2021-02-17 12:00:29
by B.Otter
Ok, I took Phil's elegant, general solution to toggling, which works with diacriticals and added code at the beginning and at the end so that:

1) if nothing selected, select one character to right of the caret

2) paste the modified text back into the document — used the clipboard.

Wondering, is there a more elegant solution to replace the toggled text than using the clipboard??

Code: Select all

# 1) code added before Phil's ToggleCase

# if no selection, select one character to right of caret
$sel_len = Selection Length
if $sel_len < 1
	$sel_loc = Selection Location 
	Select Start
	$sel_len = 1
	Set Selection $sel_loc, $sel_len
End 

### Phil’e code goes here ending with the ForEach Loop
### not included inline because the code line beginning "foreach" threw a server error on Preview

# 2) update the document with the toggle

# replace selected text in document
# this seems a brute force solution to paste text back
# overwrites then pastes the default clipboard
# I imagine there is a more elegant solution
# but I couldn't find a solution using .insertText

Write Clipboard $toggled.join('')
Edit:Paste:Paste Text Only
Select End
Brad

Re: using characterCase attribute

Posted: 2021-02-17 17:01:20
by phspaelti
Hello again Brad,
B.Otter wrote: 2021-02-17 12:00:29 1) if nothing selected, select one character to right of the caret

2) paste the modified text back into the document — used the clipboard.

Wondering, is there a more elegant solution to replace the toggled text than using the clipboard??
First to part 1. Clearly you have found a solution.
But here is an alternative. Note that the first line in my code is

Code: Select all

$sel = TextSelection.active
This creates a selection variable which you can use to check properties of the current selection, and you can also use to modify the selection:

Code: Select all

if sel.length < 1
  if $sel.location < $sel.text.length
    $sel.length = 1
    TextSelection.setActiveRange $sel.range
  else
    die 'Sorry! No space left'
  end
end
For this code to work, make sure it is placed immediately after the statement creating the $sel variable.

Now to problem 2. Again using the $sel variable, we can modify the current selection as follows:

Code: Select all

$toggledText = $toggled.join('')
$sel.text.replaceInRange $sel.range, $toggledText
You can use this code instead of the current last line of my macro "prompt..."

Re: using characterCase attribute

Posted: 2021-02-17 18:42:12
by B.Otter
Good morning, Phil, and another "Thank you." I'm going to school on your code. Liked your use of .split, .push, and .join. And this time some helpful examples of objects, selection and range. These have helped me to get a feel for the language and where to look. Like the section named "Text Object - Modifying Text" to find .replaceInRange.

Thanks for the jump start,

Brad
phspaelti wrote: 2021-02-17 17:01:20
First to part 1. Clearly you have found a solution.
But here is an alternative. Note that the first line in my code is

Code: Select all

$sel = TextSelection.active
This creates a selection variable which you can use to check properties of the current selection, and you can also use to modify the selection:

Code: Select all

if sel.length < 1
  if $sel.location < $sel.text.length
    $sel.length = 1
    TextSelection.setActiveRange $sel.range
  else
    die 'Sorry! No space left'
  end
end
For this code to work, make sure it is placed immediately after the statement creating the $sel variable.

Now to problem 2. Again using the $sel variable, we can modify the current selection as follows:

Code: Select all

$toggledText = $toggled.join('')
$sel.text.replaceInRange $sel.range, $toggledText
You can use this code instead of the current last line of my macro "prompt..."

Re: using characterCase attribute

Posted: 2021-02-17 20:56:22
by adryan
G'day, Philip et al

Thanks for another useful addition to the Macro collection, Philip.

One tiny little tweak, though, if you could: at present, it only seems to work on the first of a set of non-contiguous selections.

Cheers,
Adrian

Re: using characterCase attribute

Posted: 2021-02-17 21:58:43
by phspaelti
ToggleCase (multi).nwm
(8.05 KiB) Downloaded 969 times

Re: using characterCase attribute

Posted: 2021-02-17 23:03:40
by adryan
G'day, Philip et al

Excellent! Thanks for that, Philip.

Cheers,
Adrian