This extension provides the official code formatter for Đ (Edh)
The official formatter is no-config, uncomprised in some principles, while adapting to the rest of your code style.
By default it'll format your .edh
files on save. Use standard VSCode configuration to change this behavior:
"[edh]": {
"editor.formatOnSave": false
}
No Configuration
Don't ask anywhere.
Enforced Principles
Indention
That's to say, lines within nested brackets are always further indented, each nesting level add exactly 2 spaces to the indention; and without an enclosing bracket, a line is kept at same indention level of the line above.
Examples
method abs( x )
if x < 0 then
return -x
else
return x
will be formatted to
method abs( x )
if x < 0 then
return -x
else
return x
It's not wrong semantically, but idiomatically you are adviced to write it like this:
method abs( x ) {
if x < 0
then return -x
else return x
}
Or this:
method abs( x ) if x < 0 then -x else x
Or this:
method abs( x ) x < 0 and -x or x
Or this:
method abs( x ) {
;| x < 0 -> -x
_ -> x
}
While
for x from [ 3, 2, 5, ] do
for y from [ 7, 9, 10, ] do
yield x * y
will be formatted to:
for x from [ 3, 2, 5, ] do
for y from [ 7, 9, 10, ] do
yield x * y
which is actually idiomatic Đ style, and also:
generator long'long'arg'list (
a, b, c, d, e, f,
) {
for x from [ 3, 2, 5, ] do
for y from [ 7, 9, 10, ] do
yield ( x, y, )
}
for ( x, y )
from long'long'arg'list( 1, 2, 3, 4, 5, 6, )
do { use'x( x ) use'y( y ) }
Trailing Space
Never on a line
Even in comments and multi-line strings
While you can have it in strings
For literal strings to have trailing spaces, write each such line separately, concatenate them then, e.g.
str'with'trailing'spaces = `first line \n`
++ `middle lines
without trailing space
a line needs trailing space \n`
++ `rest lines
without trailing space
last line can have trailing spaces `
Adjacent Blank Lines
At End-Of-File:
exactly 1
Everywhere else:
0 ~ 2
Even in block comments
Margin Space
Between expressions/statements not separated by comma (,
) or semicolon (;
):
exactly 1
Between a closing bracket and following content:
exactly 1
Styles Up to You
Line Length
You decide how long each line should run, that means whether to split a long line, or to join several short lines.
Semicolons
Unlike JavaScript, neither the formatter nor the interpreter of Đ will insert semicolons for you.
But like ECMAScript 6, in most places a semicolon is not necessary, you just start writing the next expression or statement, while it's also harmless to write a semicolon as separator.
Well there're cases semicolons are necessary for disambiguation purpose.
Examples
(repl)Đ: {
Đ| 1: l = [('a', 2), ('b', 5),]
Đ| 2: x = 3
Đ| 3: ('x', x) :> l
Đ| 4: l
Đ| 5: }
❗ /fw/m3cyue/edh_modules/repl/__main__.edh:49:21
Recovered from error: 💔 traceback
📜 module:repl 👉 /fw/m3cyue/edh_modules/repl/__main__.edh:5:8-8:4
📜 module:repl 👉 <console>:2:5-3:9
💣 can not call a DecimalType: 3
ℹ️ /fw/m3cyue/edh_modules/repl/__main__.edh:56:20
Your last input may have no effect due to the error.
(repl)Đ:
Luckily els
will detect that as an error, in source files you edit with VSCode or some other supported IDE, you'll be prompted to insert a semicolon there, to end up with:
{
l = [('a', 2), ('b', 5)]
x = 3
; ('x', x) :> l
l
}
so it's correct now:
(repl)Đ: {
Đ| 1: l = [('a', 2), ('b', 5)]
Đ| 2: x = 3
Đ| 3: ; ('x', x) :> l
Đ| 4: l
Đ| 5: }
[ ( "x", 3, ), ( "a", 2, ), ( "b", 5, ), ]
(repl)Đ:
Rules of thumb
Prefix a semicolon (;
) to one of these expressions if it's not the first
expression in its scope:
- Tuple literal - to be disambiguated from procedure call
; ( a, b, c, )
- List literal - to be disambiguated from indexing
; [ a, b, c, ]
- Negation - to be disambiguated from subtraction
; -inf -> ...
- Guard - to be disambiguated from binary infix operator
|
; | null( l ) -> ...
Actually you'd prefer to always add that semicolon even if it's the first
expression, to save some trouble when later someone else or yourself to
put more expressions/statements before it.
Commas
It may be a little surprising, but commas can be omitted in Đ
Example
(repl)Đ: type( (3 2 1) )
ArgsPackType
(repl)Đ: type( [3 2 1] )
ListType
(repl)Đ: let (a b c) = (3 2 1)
(repl)Đ: (a b c) is ( a, b, c, )
true
(repl)Đ: [a b c] == [ a, b, c, ]
true
(repl)Đ: (a b c)
( 3, 2, 1, )
(repl)Đ: console.print(a b c)
3
2
1
(repl)Đ: console.print( a, b, c, )
3
2
1
(repl)Đ:
The formatter wont' insert commas for you, and neither will it remove any.
We'll figure out what a linter should say regarding commas in your code.
Trailing Commas
Trailing commas are permited by the language syntax to greatest extent, but it's up to you to write ones here and there, the formatter won't add or remove commas anyway.
String Quotes
There're actually 6 quotation marks for string literals in Đ, i.e. double quote ("
), single quote ('
), backtick (`) and the triple forms of them. All support multi-line contents.
The formatter won't queston your choice.
Neither should an Đ linter do that, for one to come sooner or later.
Margins
between keywords/identifiers and operators
It just can't be more than 1 space, you decide that 1 space to be present
or not.
Example
All these forms will be kept intact:
s = s ++ '.edh'
s =s ++ '.edh'
s= s ++ '.edh'
s=s++ '.edh'
While excessive white spaces will be thrown away by the formatter.
before an opening bracket
Note
There're curly/square/round brackets in Đ, i.e. ({}
/[]
/()
) but no angle brackets (<>
).
It's enforced no space before an opening bracket at Start-of-Line, and must 1 space if immediately following another closing bracket.
Otherwise, typically in a procedure call expression, it's up to you to decide whether to put a space between the procedure name and the opening round bracket.
Example
All of the following will be kept intact:
some'proc()
some'proc ()
some'array[ i ]
some'array [ i ]
if errno<0 then{ rethrow }
if errno < 0 then { rethrow }
Blank Lines
You can put blank lines anywhere so long as no more than 2 adjacent ones of them.
Um, plus there has to be exactly 1 blank line at EoF.