The Inbox: Morphic-ct.1733.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Morphic-ct.1733.mcz

commits-2
Christoph Thiede uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1733.mcz

==================== Summary ====================

Name: Morphic-ct.1733
Author: ct
Time: 7 March 2021, 8:42:45.180906 pm
UUID: b8246d49-b132-40af-8ad4-7428c544390c
Ancestors: Morphic-mt.1731

Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection.

=============== Diff against Morphic-mt.1731 ===============

Item was changed:
  ----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') -----
  inOutdent: aKeyboardEvent delta: delta
  "Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead.  Derived from work by Larry Tesler back in December 1985.  Now triggered by Cmd-L and Cmd-R.  2/29/96 sw"
 
  | realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize |
-
  "Operate on entire lines, but remember the real selection for re-highlighting later"
  realStart := self startIndex.
  realStop := self stopIndex - 1.
 
  "Special case a caret on a line of its own, including weird case at end of paragraph"
  (realStart > realStop and:
  [realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]])
  ifTrue:
  [delta < 0
  ifTrue:
  [morph flash]
  ifFalse:
  [self replaceSelectionWith: Character tab asText.
  self selectAt: realStart + 1].
  ^true].
 
  lines := paragraph lines.
  startLine := paragraph lineIndexOfCharacterIndex: realStart.
  "start on a real line, not a wrapped line"
  [startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1].
  stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop).
  start := (lines at: startLine) first.
  stop := (lines at: stopLine) last.
 
  "Pin the start of highlighting unless the selection starts a line"
  adjustStart := realStart > start.
 
  "Find the indentation of the least-indented non-blank line; never outdent more"
  "indentation := (startLine to: stopLine) inject: 1000 into:
  [:m :l |
  m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])].
  indentation + delta <= 0 ifTrue: [^false]."
 
  numLines := stopLine + 1 - startLine.
  oldText := paragraph text copyFrom: start to: stop.
  newText := oldText species new: oldText size + ((numLines * delta) max: 0).
 
  "Do the actual work"
  newSize := 0.
  delta > 0
  ifTrue: [| tabs |
  tabs := oldText species new: delta withAll: Character tab.
  oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
+ newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1.
- startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1].
  newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]]
  ifFalse: [| tab |
  tab := Character tab.
  oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
  | i |
  i := 0.
  [i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1].
  newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]].
  newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize].
 
  "Adjust the range that will be highlighted later"
  adjustStart ifTrue: [realStart := (realStart + delta) max: start].
  realStop := realStop + newSize - oldText size.
 
  "Replace selection"
  self selectInvisiblyFrom: start to: stop.
  self replaceSelectionWith: newText.
  self selectFrom: realStart to: realStop. "highlight only the original range"
  ^ true!


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Morphic-ct.1733.mcz

marcel.taeumel
Hi Christoph,

why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character.

Best,
Marcle

Am 07.03.2021 20:43:09 schrieb [hidden email] <[hidden email]>:

Christoph Thiede uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1733.mcz

==================== Summary ====================

Name: Morphic-ct.1733
Author: ct
Time: 7 March 2021, 8:42:45.180906 pm
UUID: b8246d49-b132-40af-8ad4-7428c544390c
Ancestors: Morphic-mt.1731

Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection.

=============== Diff against Morphic-mt.1731 ===============

Item was changed:
----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') -----
inOutdent: aKeyboardEvent delta: delta
"Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw"

| realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize |
-
"Operate on entire lines, but remember the real selection for re-highlighting later"
realStart := self startIndex.
realStop := self stopIndex - 1.

"Special case a caret on a line of its own, including weird case at end of paragraph"
(realStart > realStop and:
[realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]])
ifTrue:
[delta < 0
ifTrue:
[morph flash]
ifFalse:
[self replaceSelectionWith: Character tab asText.
self selectAt: realStart + 1].
^true].

lines := paragraph lines.
startLine := paragraph lineIndexOfCharacterIndex: realStart.
"start on a real line, not a wrapped line"
[startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1].
stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop).
start := (lines at: startLine) first.
stop := (lines at: stopLine) last.

"Pin the start of highlighting unless the selection starts a line"
adjustStart := realStart > start.

"Find the indentation of the least-indented non-blank line; never outdent more"
"indentation := (startLine to: stopLine) inject: 1000 into:
[:m :l |
m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])].
indentation + delta <= 0 ifTrue: [^false]."

numLines := stopLine + 1 - startLine.
oldText := paragraph text copyFrom: start to: stop.
newText := oldText species new: oldText size + ((numLines * delta) max: 0).

"Do the actual work"
newSize := 0.
delta > 0
ifTrue: [| tabs |
tabs := oldText species new: delta withAll: Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
+ newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1.
- startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]]
ifFalse: [| tab |
tab := Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
| i |
i := 0.
[i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]].
newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize].

"Adjust the range that will be highlighted later"
adjustStart ifTrue: [realStart := (realStart + delta) max: start].
realStop := realStop + newSize - oldText size.

"Replace selection"
self selectInvisiblyFrom: start to: stop.
self replaceSelectionWith: newText.
self selectFrom: realStart to: realStop. "highlight only the original range"
^ true!




Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Morphic-ct.1733.mcz

marcel.taeumel
Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented.

Best,
Marcel

Am 08.03.2021 10:52:54 schrieb Marcel Taeumel <[hidden email]>:

Hi Christoph,

why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character.

Best,
Marcle

Am 07.03.2021 20:43:09 schrieb [hidden email] <[hidden email]>:

Christoph Thiede uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1733.mcz

==================== Summary ====================

Name: Morphic-ct.1733
Author: ct
Time: 7 March 2021, 8:42:45.180906 pm
UUID: b8246d49-b132-40af-8ad4-7428c544390c
Ancestors: Morphic-mt.1731

Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection.

=============== Diff against Morphic-mt.1731 ===============

Item was changed:
----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') -----
inOutdent: aKeyboardEvent delta: delta
"Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw"

| realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize |
-
"Operate on entire lines, but remember the real selection for re-highlighting later"
realStart := self startIndex.
realStop := self stopIndex - 1.

"Special case a caret on a line of its own, including weird case at end of paragraph"
(realStart > realStop and:
[realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]])
ifTrue:
[delta < 0
ifTrue:
[morph flash]
ifFalse:
[self replaceSelectionWith: Character tab asText.
self selectAt: realStart + 1].
^true].

lines := paragraph lines.
startLine := paragraph lineIndexOfCharacterIndex: realStart.
"start on a real line, not a wrapped line"
[startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1].
stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop).
start := (lines at: startLine) first.
stop := (lines at: stopLine) last.

"Pin the start of highlighting unless the selection starts a line"
adjustStart := realStart > start.

"Find the indentation of the least-indented non-blank line; never outdent more"
"indentation := (startLine to: stopLine) inject: 1000 into:
[:m :l |
m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])].
indentation + delta <= 0 ifTrue: [^false]."

numLines := stopLine + 1 - startLine.
oldText := paragraph text copyFrom: start to: stop.
newText := oldText species new: oldText size + ((numLines * delta) max: 0).

"Do the actual work"
newSize := 0.
delta > 0
ifTrue: [| tabs |
tabs := oldText species new: delta withAll: Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
+ newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1.
- startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]]
ifFalse: [| tab |
tab := Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
| i |
i := 0.
[i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]].
newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize].

"Adjust the range that will be highlighted later"
adjustStart ifTrue: [realStart := (realStart + delta) max: start].
realStop := realStop + newSize - oldText size.

"Replace selection"
self selectInvisiblyFrom: start to: stop.
self replaceSelectionWith: newText.
self selectFrom: realStart to: realStop. "highlight only the original range"
^ true!




Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Morphic-ct.1733.mcz

Christoph Thiede

Hi Marcel,


most editors support both ways through configuration.


I fear that's stuff for a principal debate, just like "tabs vs spaces" ... So let the games begin! :D


Most methods in Squeak are formatted with empty lines indented just like their surrounding lines, and this also matches my own preference. This has a number of advantages:


1. It's just more consistent that every line that is part of a logic unit (e.g. block, expression, or array) is indented in the same way, without defining any special treatments for empty lines.

2. If you fill an empty line with some statement, the indentation is already there and you do not need to correct (i.e. add) it.

3. If you remove a statement from an empty line, you do not need to "correct" (i.e. remove) the indentation.

4. It's easier to navigate through all lines with the caret because it does not jump back to the unintended beginning of a line.

5. Auto-generation is easier because we don't have an edge case for empty lines.


But I know that the party of the "no-empty-indenters" also has at least one counterargument because they call these indentations trailing whitespace.


Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented.


And here's where the special treatments (cf. arg 1 above) would begin. If every line in a method (except the signature) has a minimum indentation of one, why should empty lines deserve a negative indentation of 1 compared to the default? If you have a method like this where the default indentation is effectively 2, why should empty lines only be intended with 1 tab?

treat: something
    something ifNotNil: [
        something foo.
        something bar.
        
        something baz].

For these reasons, I think indenting every line consistently would just be more consistent. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Montag, 8. März 2021 10:55:19
An: squeak-dev
Betreff: Re: [squeak-dev] The Inbox: Morphic-ct.1733.mcz
 
Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented.

Best,
Marcel

Am 08.03.2021 10:52:54 schrieb Marcel Taeumel <[hidden email]>:

Hi Christoph,

why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character.

Best,
Marcle

Am 07.03.2021 20:43:09 schrieb [hidden email] <[hidden email]>:

Christoph Thiede uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1733.mcz

==================== Summary ====================

Name: Morphic-ct.1733
Author: ct
Time: 7 March 2021, 8:42:45.180906 pm
UUID: b8246d49-b132-40af-8ad4-7428c544390c
Ancestors: Morphic-mt.1731

Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection.

=============== Diff against Morphic-mt.1731 ===============

Item was changed:
----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') -----
inOutdent: aKeyboardEvent delta: delta
"Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw"

| realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize |
-
"Operate on entire lines, but remember the real selection for re-highlighting later"
realStart := self startIndex.
realStop := self stopIndex - 1.

"Special case a caret on a line of its own, including weird case at end of paragraph"
(realStart > realStop and:
[realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]])
ifTrue:
[delta < 0
ifTrue:
[morph flash]
ifFalse:
[self replaceSelectionWith: Character tab asText.
self selectAt: realStart + 1].
^true].

lines := paragraph lines.
startLine := paragraph lineIndexOfCharacterIndex: realStart.
"start on a real line, not a wrapped line"
[startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1].
stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop).
start := (lines at: startLine) first.
stop := (lines at: stopLine) last.

"Pin the start of highlighting unless the selection starts a line"
adjustStart := realStart > start.

"Find the indentation of the least-indented non-blank line; never outdent more"
"indentation := (startLine to: stopLine) inject: 1000 into:
[:m :l |
m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])].
indentation + delta <= 0 ifTrue: [^false]."

numLines := stopLine + 1 - startLine.
oldText := paragraph text copyFrom: start to: stop.
newText := oldText species new: oldText size + ((numLines * delta) max: 0).

"Do the actual work"
newSize := 0.
delta > 0
ifTrue: [| tabs |
tabs := oldText species new: delta withAll: Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
+ newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1.
- startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]]
ifFalse: [| tab |
tab := Character tab.
oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL |
| i |
i := 0.
[i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1].
newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]].
newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize].

"Adjust the range that will be highlighted later"
adjustStart ifTrue: [realStart := (realStart + delta) max: start].
realStop := realStop + newSize - oldText size.

"Replace selection"
self selectInvisiblyFrom: start to: stop.
self replaceSelectionWith: newText.
self selectFrom: realStart to: realStop. "highlight only the original range"
^ true!




Carpe Squeak!