PR# 19916 Last line in verbatim strings

Problem Report Summary
Submitter: gobobe
Category: Compiler
Priority: Low
Date: 2024/04/19
Class: Bug
Severity: Non-critical
Number: 19916
Release: 23.09.10.7341
Confidential: No
Status: Closed
Responsible:
Environment: win
Synopsis: Last line in verbatim strings

Description
In verbatim strings using `"[` and `]"`, the longest common indentation is removed from all lines.
In addition to that, the ISE Eiffel compiler also removes the last line if it is empty, although I cannot see this behavior described in the ECMA standard.
For compatibility, the Gobo Eiffel compiler also removes the last line if it is empty. But I just discovered that what it means for the last line to be empty is different between the two compilers.
This is what I observed. Let's consider Ind(n) the longest common indentation for all lines in the verbatim string, and Ind(n-1) the longest common indentation for all lines in the verbatim string except the last line.
Behavior with ISE Eiffel:
  * Remove Ind(n) from all lines.
  * If the last line is a subset of Ind(n-1) then removes this line.
Behavior with Gobo Eiffel:
  * If the last line is a subset of Ind(n-1) then removes this line.
  * Remove Ind(n-1) from the remaining lines.
This means that if the last line has no characters, it will be removed by both compilers, but the indentation on the remaining lines will not be removed by ISE Eiffel whereas it will be removed by Gobo Eiffel.
To Reproduce
Compile `ecb` with the Gobo Eiffel compiler, and run `ecb -help`. We get:
```
ISE EiffelStudio version 22.12.0.0000 - win64

Usage:
        C:\ise\GPL\ecb.exe -help | -version | -full |
-batch | -clean | -verbose | -use_settings |
-freeze | -finalize [-keep] | -precompile [-finalize [-keep]] | -c_compile |
-loop | -debug | -quick_melt | -melt |
(-clients | -suppliers | -ancestors | -descendants) [-filter filtername] class |
(-flatshort | -flat | -short) [-filter filtername] [-all | -all_and_parents | class] |
(-aversions | -dversions | -implementers) [-filter filtername] class feature |
-callers [-filter filtername] [-show_all] [-assigners | -creators] class feature |
-callees [-filter filtername] [-show_all] [-assignees | -creators] class feature |
-filter filtername [-all | class] |
-pretty input_filename [output_filename] |
-reset_ide_layout |
[[-config config.ecf] [-target target] [-config_option option] |
[class_file.e [-library library_name]] |
-stop | -no_library |
-project_path project_directory | -file file |
-preference preference_name preference_value |
-ca_class (-all | class) | -ca_default | -ca_rule rule | -ca_setting file |
-gc_stats]

Options:
        default (no option): quick melt the system.

        -ancestors: show the ancestors of a class.
        -aversions: show the ancestor versions of a feature.
        -batch: launch the compilation without user request.
        -c_compile: launch C compilation if needed.
        -ca_class: analyze code of a class or of all non-library classes (-all).
        -ca_default: restore default code analyzer preferences.
        -ca_rule: activate code analyzer rule(s) (with settings).
        -ca_setting: load code analyzer preferences from a file.
        -callees: show the callees of a feature.
        -callers: show the callers of a feature.
        -class_file.e: specify a class file for single file compilation.
        -clean: delete existing project if any and perform a fresh compilation.
        -clients: show the clients of a class.
        -config: specify the configuration (ECF) file.
        -config_option: override configuration options of a target.
        -debug: debug the system as a command loop.
        -descendants: show the descendants of a class.
        -dversions: show the descendant versions of a feature.
        -file: save the output to a file.
        -filter: show a filtered form (troff, ...) of the class text.
        -finalize: finalize the system (discard assertions by default).
        -flat: show the flat form of a class.
        -flatshort: show the flat-short form of a class.
        -freeze: freeze the system.
        -full: with full class checking regardless of ECF settings.
        -gc_stats: Show GC statistics.
        -gui: start the graphical environment.
        -help: show this help message.
        -implementers: show the classes implementing a feature.
        -library: specify a library for single file compilation.
        -loop: run ec as a command loop.
        -melt: melt the system.
        -no_library: do not convert clusters into libraries.
        -overwrite_old_project: overwrite any existing old project.
        -precompile: precompile the system.
        -preference: override default or stored preference value.
        -pretty: show the pretty form of a class.
        -project: specify the project file to load (obsolete).
        -project_path: specify the compilation directory.
        -quick_melt: quick melt the system.
        -reset_ide_layout: reset the IDE layout.
        -short: show the short form of a class.
        -stop: stop on error.
        -suppliers: show the suppliers of a class.
        -target: specify the target.
        -use_settings: use settings for project location.
        -version: show compiler version number.
```

Execute the same command with the version of `ecb` from the 22.12 or 23.09 distribution. We get:
```
ISE EiffelStudio version 22.12.10.6463 - win64

Usage:
        C:\Eiffel\ise\22.12.10.6463\studio\spec\win64\bin\ecb.exe                                 -help | -version | -full |
                                -batch | -clean | -verbose | -use_settings |
                                -freeze | -finalize [-keep] | -precompile [-finalize [-keep]] | -c_compile |
                                -loop | -debug | -quick_melt | -melt |
                                (-clients | -suppliers | -ancestors | -descendants) [-filter filtername] class |
                                (-flatshort | -flat | -short) [-filter filtername] [-all | -all_and_parents | class] |
                                (-aversions | -dversions | -implementers) [-filter filtername] class feature |
                                -callers [-filter filtername] [-show_all] [-assigners | -creators] class feature |
                                -callees [-filter filtername] [-show_all] [-assignees | -creators] class feature |
                                -filter filtername [-all | class] |
                                -pretty input_filename [output_filename] |
                                -reset_ide_layout |
                                [[-config config.ecf] [-target target] [-config_option option] |
                                [class_file.e [-library library_name]] |
                                -stop | -no_library |
                                -project_path project_directory | -file file |
                                -preference preference_name preference_value |
                                -ca_class (-all | class) | -ca_default | -ca_rule rule | -ca_setting file |
                                -gc_stats]

Options:
        default (no option): quick melt the system.

        -ancestors: show the ancestors of a class.
        -aversions: show the ancestor versions of a feature.
        -batch: launch the compilation without user request.
        -c_compile: launch C compilation if needed.
        -ca_class: analyze code of a class or of all non-library classes (-all).
        -ca_default: restore default code analyzer preferences.
        -ca_rule: activate code analyzer rule(s) (with settings).
        -ca_setting: load code analyzer preferences from a file.
        -callees: show the callees of a feature.
        -callers: show the callers of a feature.
        -class_file.e: specify a class file for single file compilation.
        -clean: delete existing project if any and perform a fresh compilation.
        -clients: show the clients of a class.
        -config: specify the configuration (ECF) file.
        -config_option: override configuration options of a target.
        -debug: debug the system as a command loop.
        -descendants: show the descendants of a class.
        -dversions: show the descendant versions of a feature.
        -file: save the output to a file.
        -filter: show a filtered form (troff, ...) of the class text.
        -finalize: finalize the system (discard assertions by default).
        -flat: show the flat form of a class.
        -flatshort: show the flat-short form of a class.
        -freeze: freeze the system.
        -full: with full class checking regardless of ECF settings.
        -gc_stats: Show GC statistics.
        -gui: start the graphical environment.
        -help: show this help message.
        -implementers: show the classes implementing a feature.
        -library: specify a library for single file compilation.
        -loop: run ec as a command loop.
        -melt: melt the system.
        -no_library: do not convert clusters into libraries.
        -overwrite_old_project: overwrite any existing old project.
        -precompile: precompile the system.
        -preference: override default or stored preference value.
        -pretty: show the pretty form of a class.
        -project: specify the project file to load (obsolete).
        -project_path: specify the compilation directory.
        -quick_melt: quick melt the system.
        -reset_ide_layout: reset the IDE layout.
        -short: show the short form of a class.
        -stop: stop on error.
        -suppliers: show the suppliers of a class.
        -target: specify the target.
        -use_settings: use settings for project location.
        -version: show compiler version number.
```

The corresponding Eiffel code in class `ES` looks like this:
```
	print_usage
			-- Print the usage of command line options.
		do
			print_version
			io.put_new_line
			localized_print (ewb_names.usage)
			localized_print (argument (0))
				-- The leading space on the first line is required to delimit options from the command name.
			io.put_string ("[
				 -help | -version | -full |
				-batch | -clean | -verbose | -use_settings |
				-freeze | -finalize [-keep] | -precompile [-finalize [-keep]] | -c_compile |
				-loop | -debug | -quick_melt | -melt |
				(-clients | -suppliers | -ancestors | -descendants) [-filter filtername] class |
				(-flatshort | -flat | -short) [-filter filtername] [-all | -all_and_parents | class] |
				(-aversions | -dversions | -implementers) [-filter filtername] class feature |
				-callers [-filter filtername] [-show_all] [-assigners | -creators] class feature |
				-callees [-filter filtername] [-show_all] [-assignees | -creators] class feature |
				-filter filtername [-all | class] |
				-pretty input_filename [output_filename] |
				-reset_ide_layout |
				[[-config config.ecf] [-target target] [-config_option option] |
				[class_file.e [-library library_name]] |
				-stop | -no_library |
				-project_path project_directory | -file file |
				-preference preference_name preference_value |
				-ca_class (-all | class) | -ca_default | -ca_rule rule | -ca_setting file |
				-gc_stats]

			]")
		end
```

with no character on the last line of the verbatim string.

--
Eric Bezault

Problem Report Interactions
From:jfiat_es    Date:2024/05/02    Status: Closed    Download   
The help message was fixed by revision rev#107752, and the indentation is now a 2 spaces indentation instead of tabs to have more compact help message.

From:gobobe    Date:2024/04/19    Status: Open    Download   
See pull request `https://github.com/EiffelSoftware/EiffelStudio/pull/61` .

--
Eric Bezault

From:gobobe    Date:2024/04/19    Status: Open    Download   
From what Git tells me, the wrong indentation in the help message was introduced in:

```
Jocelyn Fiat, 4 years ago   (April 8th, 2020 10:17 AM) 
Added command line option `-reset_ide_layout` to reset the IDE layout (mostly docking setting for now, usually to recover from bad crash).
git-svn-id: https://svn.eiffel.com/eiffelstudio-public/trunk@104034 8089f293-4706-0410-a29e-feb5c42a2edf
```

where the tabs on the last line of the verbatim string have been removed (most likely automatically when saving from EiffelStudio).

--
Eric Bezault