Compare commits

...

54 commits

Author SHA1 Message Date
Nicholas Wilson
d8e43e23ec remove explicit nothrow from globMatchEditorConfig
The in contract may throw.
2024-08-21 09:58:22 +02:00
Andrei Horodniceanu
0ea0572e86 makefile: Remove stdx-allocator from imports and sources
Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
2024-05-11 20:07:03 +02:00
Andrei Horodniceanu
5ea76cd293 makefile: fix bin/dfmt-test target
Don't call the D compiler with bin/githash.txt as a source file.

Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
2024-05-11 20:07:03 +02:00
Jeremy Baxter
fa463b472c improve makefile
o  add 'install' target
 o  shorten the name of INCLUDE_PATHS to IMPORTS
 o  use filename prerequisities and targets rather than phony keywords
 o  add a dependency on .git/refs/tags for the githash target
 o  add githash.txt and dfmt-test to the clean target
 o  add more targets to .PHONY
2024-02-15 10:41:02 +01:00
Daniel Zuncke
2ea6c43a66 Use libdparse to check for named arg
Remove custom named arg parser
2023-10-26 20:10:50 +00:00
Daniel Zuncke
9f377100f0 Remove unnecessary tok!"comment" filter 2023-10-26 20:10:50 +00:00
Daniel Zuncke
20b8badf8c Fix issue #586 2023-10-26 20:10:50 +00:00
Daniel Zuncke
35e55bc9b2
Fix #578 ternary expressions in AA literals not properly formatted (#591) 2023-10-22 17:52:14 +09:00
Daniel Zuncke
08fe5d6855 Confirm token equality, safer loop
Using different variable to iterate to guarantee unchanged behaviour
if anything doesn't work as intended.
2023-10-18 10:22:48 +02:00
Daniel Zuncke
c0452dbd11 Update test to include both known cases
I have formatted them both to look like the the individual bad output
and not like the actual output from formatting the issue0432.d file with
the current implementation. The current implementation makes it look
like a new / different problem.
2023-10-18 10:22:48 +02:00
Daniel Zuncke
876bbe33c1 Fix issue #432
Overview:
Array astInformation.structInitEndLocations is used to find index to use
in astInformation.indentInfoSortedByEndLocation.
Both are sorted, first is used to find the array index, second is
accessed at that index to get brace indentation information.

Problem:
structInitEndLocations is generated from struct initializers
exclusively while the brace information array also contains entries
for function literal initializers. Thus when function literal init(s)
are used, we get accumulating off by one errors in the second array:

match value in structInitEndLocations and take that index:
[3, 50]
    ^--> index 1

take brace indent information from that index:
[3, 15, 50]
    |   ^--> the one we want
    ^------> the one we get (function literal init)

Solution:
This guarantees that searching forward works.
While better search strategies than linear are possible, this should be
enough for any sane and most of the insane code files.
2023-10-18 10:22:48 +02:00
WebFreak001
1e765fb781 add knr test variant for no_space_after_keyword
The generator is so outdated and basic that it didn't generate this.
2023-07-26 16:13:48 +02:00
Robert Schadek
c43803575d No space after keywords
Readme update

test files
2023-07-26 16:13:48 +02:00
WebFreak001
470e65f7cc bump minimum libdparse version, fix #583 2023-07-19 14:43:24 +02:00
Eugen Wissner
6f41b20d5b Remove travis 2023-05-01 23:01:54 +02:00
Razvan Nitu
49b9fe4051
Merge pull request #579 from belka-ew/bug/revert-array-indent-on-line
Keep "(" indentation with a "]" in the same line
2023-04-07 23:19:48 +08:00
Eugen Wissner
fec7394175 Add reflow_property_chains option
Recalculate the splitting of property chains into multiple lines.
2023-03-29 11:29:59 +02:00
Eugen Wissner
727472c365
Keep "(" indentation with a "]" in the same line 2023-03-20 18:23:33 +01:00
WebFreak001
840aeee45e add missing test 2023-03-01 22:07:37 +01:00
WebFreak001
a91f044958 add some missing hasCurrent checks 2023-03-01 22:07:37 +01:00
Eugen Wissner
dba8c87ebc Revert operator indentation in an argument list 2023-02-06 10:17:09 +01:00
Eugen Wissner
a4fbc6f881 Revert chain indentation in an argument list 2023-01-15 20:51:03 +01:00
Eugen Wissner
57f57d95de Fix else indentation after array literal 2023-01-14 02:18:28 +01:00
WebFreak001
4a6078779a Fix #568, don't output empty files without error
Now when an error in formatting happens, it never outputs anything and
doesn't override the file when working inplace.

Additionally dfmt is no longer able to fail in the middle of a file, as
now we first write everything to a buffer and only if everything was
successful, that buffer is printed to stdout or written to the inplace
file.

This should also guard against segfaults with inplace file formatting
erasing parts of the file, as well as the user thinking it was
successful, even though dfmt didn't finish properly.
2022-10-15 02:33:04 +02:00
Iain Buclaw
e251e4343a Remove appveyor.yml
This pipeline isn't in use anymore.
2022-10-06 21:10:01 +02:00
Iain Buclaw
02070df593 Update downloads.dlang.org links to use https 2022-10-06 21:10:01 +02:00
Andrey Proskurin
6744df20f3 Add knr brace style to README 2022-09-14 13:25:04 +02:00
Eugen Wissner
8d42254d47 Fix indentation of callchains with comments
Weird formatting and indentation of multiline callchains with comments
in the middle.
2022-08-06 08:55:43 +02:00
Bastiaan Veelo
2a4af7a2b2
Retain line ending by default. (#553) 2022-07-28 17:21:10 +02:00
Eugen Wissner
026a58e273 Very long chained calls in array literals are indented weirdly 2022-07-28 17:14:01 +02:00
Bastiaan Veelo
4947beec6b CI
Add GitHub action.
2022-07-14 23:19:37 +02:00
belka-ew
d862d8aef1
Fix array literal indentation in foreach (#554) 2022-06-14 12:35:54 +00:00
skyline131313
036da91542
Update dub.json to remove dependency on rdmd (#547) 2022-06-13 16:23:56 +02:00
Max Haughton
ed5fc2ffd2
Merge pull request #551 from veelo/d_test_script
Port `test.sh` to platform independent D.
2022-05-30 00:15:49 +01:00
Bastiaan Veelo
b8da7c5cd4 Refactor courtesy WebFreak001.
Co-authored-by: Jan Jurzitza <gh@webfreak.org>
2022-05-27 19:47:47 +02:00
Bastiaan Veelo
f6d9d04e43 Port test.sh to platform independent D.
This executes also way faster by not spawning GNU diff.
2022-05-26 16:10:07 +02:00
Bastiaan Veelo
f81ddeadbd
obey end_of_line setting in all tokens (#550)
Multi-line tokens would be written with `LF`, regardless the `end_of_line` setting.

Fixes #228 and also produces end_of_line specified line-endings in strings.
2022-05-25 13:21:07 +02:00
Bastiaan Veelo
3e1e643972
Merge branch 'dlang-community:master' into master 2022-05-23 16:23:20 +02:00
Eugen Wissner
77e2ba4e3d Fix array indentation as argument 2022-05-23 14:09:26 +02:00
RazvanN7
6a24f0dc7c Upgrade libdparse to latest version 2022-01-26 14:05:44 +01:00
Martin Kinkelin
b776d5a9b9 Fix tests 2021-10-31 20:37:32 +09:00
Razvan Nitu
2beb819851
Merge pull request #535 from dlang-community/single-indent
Add single_indent option
2021-10-22 16:22:40 +03:00
Jan Jurzitza
f1e57135bb
Merge pull request #534 from dlang-community/knr_brace_style 2021-10-09 09:09:50 +02:00
Max Haughton
e5e11604f0
Merge pull request #542 from belka-ew/comment-before-contract
Fix comment before contract
2021-09-07 16:46:42 +01:00
Eugen Wissner
e8bd41c70d
Fix comment before contract
Fixes #451.
2021-09-07 14:29:45 +02:00
Sönke Ludwig
b3b8ff1a43 Avoid possible null pointer access. 2021-08-16 18:09:57 +02:00
Amin Yahyaabadi
0e5615e13e
Fix the CLI help output about the --config option (#541) 2021-08-04 00:40:22 +03:00
belka-ew
f6490b31c9
Format multiline arrays first (#538) 2021-06-16 17:23:27 +03:00
Eugen Wissner
995c21ab87 Format do like body after function attributes 2021-06-14 21:06:32 +00:00
Eugen Wissner
821b9be9e9 Fix double array indentation inside parens 2021-06-12 05:39:30 +00:00
Eugen Wissner
ea36fbf58b
Add single_indent option 2021-05-18 06:36:57 +02:00
Sönke Ludwig
0f61586438 Add tests for "knr" brace style. 2021-04-16 13:57:59 +02:00
Sönke Ludwig
e35bde0815 Add Kernighan & Ritchie style brace formatting.
The original K&R style behaves like BraceStyle.otbs, except for function definitions that use Allman style.
2021-04-16 13:57:21 +02:00
Bastiaan Veelo
5274e5531e
Merge pull request #1 from dlang-community/master
Allow comments in selective imports. (#403)
2018-10-29 12:04:52 +01:00
350 changed files with 4975 additions and 453 deletions

16
.gitattributes vendored Normal file
View file

@ -0,0 +1,16 @@
tests/issue0228.d text eol=lf
tests/allman/issue0228.d.ref text eol=crlf
tests/knr/issue0228.d.ref text eol=crlf
tests/otbs/issue0228.d.ref text eol=crlf
tests/issue0552_lf.d text eol=lf
tests/allman/issue0552_lf.d.ref text eol=lf
tests/knr/issue0552_lf.d.ref text eol=lf
tests/otbs/issue0552_lf.d.ref text eol=lf
tests/issue0552_cr.d text eol=cr
tests/allman/issue0552_cr.d.ref text eol=cr
tests/knr/issue0552_cr.d.ref text eol=cr
tests/otbs/issue0552_cr.d.ref text eol=cr
tests/issue0552_crlf.d text eol=crlf
tests/allman/issue0552_crlf.d.ref text eol=crlf
tests/knr/issue0552_crlf.d.ref text eol=crlf
tests/otbs/issue0552_crlf.d.ref text eol=crlf

34
.github/workflows/d.yml vendored Normal file
View file

@ -0,0 +1,34 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: D
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dlang-community/setup-dlang@4c99aa991ce7d19dd3064de0a4f2f6b2f152e2d7
- name: 'Build & Test'
run: |
# Build the project, with its main file included, without unittests
dub build --compiler=$DC
# Build and run tests, as defined by `unittest` configuration
# In this mode, `mainSourceFile` is excluded and `version (unittest)` are included
# See https://dub.pm/package-format-json.html#configurations
dub test --compiler=$DC
# Run tests
cd tests && rdmd test

View file

@ -1,15 +0,0 @@
#!/bin/bash
set -e
if [[ $BUILD == dub ]]; then
rdmd ./d-test-utils/test_with_package.d $LIBDPARSE_VERSION libdparse -- dub build --build=release
elif [[ $DC == ldc2 ]]; then
git submodule update --init --recursive
make ldc -j2
else
git submodule update --init --recursive
make debug -j2
fi
cd tests && ./test.sh

View file

@ -1,95 +0,0 @@
sudo: false
language: d
d:
- dmd
- ldc
os:
- linux
- osx
branches:
only:
- master
- /^v\d+\.\d+\.\d+([+-]\S*)*$/
env:
- BUILD=
- BUILD=dub LIBDPARSE_VERSION=min
- BUILD=dub LIBDPARSE_VERSION=max
script: ./.travis.sh
jobs:
include:
- stage: GitHub Release
#if: tag IS present
d: ldc-1.13.0
os: linux
script: echo "Deploying to GitHub releases ..." && ./release.sh
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.tar.gz
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
- stage: GitHub Release
#if: tag IS present
d: ldc-1.13.0
os: osx
script: echo "Deploying to GitHub releases ..." && ./release.sh
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.tar.gz
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
- stage: GitHub Release
#if: tag IS present
d: dmd
os: linux
language: generic
sudo: yes
script: echo "Deploying to GitHub releases ..." && ./release-windows.sh
addons:
apt:
packages:
- p7zip-full
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.zip
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
- stage: GitHub Release
#if: tag IS present
d: dmd
os: linux
language: generic
sudo: yes
script: echo "Deploying to GitHub releases ..." && ARCH=64 ./release-windows.sh
addons:
apt:
packages:
- p7zip-full
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.zip
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
stages:
- name: test
if: type = pull_request or (type = push and branch = master)

View file

@ -1,4 +1,5 @@
# dfmt [![Build Status](https://travis-ci.org/dlang-community/dfmt.svg?branch=master)](https://travis-ci.org/dlang-community/dfmt)
# dfmt [![Build Status](https://github.com/dlang-community/dfmt/actions/workflows/d.yml/badge.svg)](https://github.com/dlang-community/dfmt/actions?query=workflow%3A%22D%22)
**dfmt** is a formatter for D source code
## Status
@ -51,11 +52,15 @@ found there.
* `--soft_max_line_length`: *see dfmt_soft_max_line_length [below](#dfmt-specific-properties)*
* `--space_after_cast`: *see dfmt_space_after_cast [below](#dfmt-specific-properties)*
* `--space_before_aa_colon`: *see dfmt_space_before_aa_colon [below](#dfmt-specific-properties)*
* `--space_before_named_arg_colon`: *see dfmt_space_before_named_arg_colon [below](#dfmt-specific-properties)*
* `--space_before_function_parameters`: *see dfmt_space_before_function_parameters [below](#dfmt-specific-properties)*
* `--split_operator_at_line_end`: *see dfmt_split_operator_at_line_end [below](#dfmt-specific-properties)*
* `--tab_width`: *see tab_width [below](#standard-editorconfig-properties)*
* `--template_constraint_style`: *see dfmt_template_constraint_style [below](#dfmt-specific-properties)*
* `--keep_line_breaks`: *see dfmt_keep_line_breaks [below](#dfmt-specific-properties)*
* `--single_indent`: *see dfmt_single_indent [below](#dfmt-specific-properties)*
* `--reflow_property_chains`: *see dfmt_property_chains [below](#dfmt-specific-properties)*
* `--space_after_keywords`: *see dfmt_space_after_keywords [below](#dfmt-specific-properties)*
### Example
```
@ -91,7 +96,7 @@ void main(string[] args)
### Standard EditorConfig properties
Property Name | Allowed Values | Description
--------------|----------------|------------
end_of_line | `cr`, `crlf` and **`lf`** | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#end_of_line)
end_of_line | `cr`, `crlf` and `lf` | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#end_of_line) When not set, `dfmt` adopts the first line ending in the input.
insert_final_newline | **`true`** | Not supported. `dfmt` always inserts a final newline.
charset | **`UTF-8`** | Not supported. `dfmt` only works correctly on UTF-8.
indent_style | `tab`, **`space`** | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#indent_style)
@ -102,7 +107,7 @@ max_line_length | positive integers (**`120`**) | [See EditorConfig documentatio
### dfmt-specific properties
Property Name | Allowed Values | Description
--------------|----------------|------------
dfmt_brace_style | **`allman`**, `otbs`, or `stroustrup` | [See Wikipedia](https://en.wikipedia.org/wiki/Brace_style)
dfmt_brace_style | **`allman`**, `otbs`, `stroustrup` or `knr` | [See Wikipedia](https://en.wikipedia.org/wiki/Brace_style)
dfmt_soft_max_line_length | positive integers (**`80`**) | The formatting process will usually keep lines below this length, but they may be up to *max_line_length* columns long.
dfmt_align_switch_statements | **`true`**, `false` | Align labels, cases, and defaults with their enclosing switch.
dfmt_outdent_attributes (Not yet implemented) | **`true`**, `false`| Decrease the indentation level of attributes.
@ -115,7 +120,11 @@ dfmt_compact_labeled_statements | **`true`**, `false` | Place labels on the same
dfmt_template_constraint_style | **`conditional_newline_indent`** `conditional_newline` `always_newline` `always_newline_indent` | Control the formatting of template constraints.
dfmt_single_template_constraint_indent | `true`, **`false`** | Set if the constraints are indented by a single tab instead of two. Has only an effect if the style set to `always_newline_indent` or `conditional_newline_indent`.
dfmt_space_before_aa_colon | `true`, **`false`** | Adds a space after an associative array key before the `:` like in older dfmt versions.
dfmt_space_before_named_arg_colon | `true`, **`false`** | Adds a space after a named function argument or named struct constructor argument before the `:`.
dfmt_keep_line_breaks | `true`, **`false`** | Keep existing line breaks if these don't violate other formatting rules.
dfmt_single_indent | `true`, **`false`** | Set if the code in parens is indented by a single tab instead of two.
dfmt_reflow_property_chains | **`true`**, `false` | Recalculate the splitting of property chains into multiple lines.
dfmt_space_after_keywords | **`true`**, `false` | Insert space after keywords (if,while,foreach,for, etc.).
## Terminology
* Braces - `{` and `}`

View file

@ -1,112 +0,0 @@
platform: x64
environment:
matrix:
- DC: dmd
DVersion: stable
arch: x64
- DC: dmd
DVersion: stable
arch: x86
# - DC: ldc
# DVersion: beta
# arch: x86
# - DC: ldc
# DVersion: beta
# arch: x64
# - DC: ldc
# DVersion: stable
# arch: x86
# - DC: ldc
# DVersion: stable
# arch: x64
skip_tags: false
branches:
only:
- master
- /^v\d+\.\d+\.\d+([+-]\S*)*$/
install:
- ps: function ResolveLatestDMD
{
$version = $env:DVersion;
if($version -eq "stable") {
$latest = (Invoke-WebRequest "http://downloads.dlang.org/releases/LATEST").toString();
$url = "http://downloads.dlang.org/releases/2.x/$($latest)/dmd.$($latest).windows.7z";
}elseif($version -eq "beta") {
$latest = (Invoke-WebRequest "http://downloads.dlang.org/pre-releases/LATEST").toString();
$latestVersion = $latest.split("-")[0].split("~")[0];
$url = "http://downloads.dlang.org/pre-releases/2.x/$($latestVersion)/dmd.$($latest).windows.7z";
}elseif($version -eq "nightly") {
$url = "http://nightlies.dlang.org/dmd-master-2017-05-20/dmd.master.windows.7z"
}else {
$url = "http://downloads.dlang.org/releases/2.x/$($version)/dmd.$($version).windows.7z";
}
$env:PATH += ";C:\dmd2\windows\bin;";
return $url;
}
- ps: function ResolveLatestLDC
{
$version = $env:DVersion;
if($version -eq "stable") {
$latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST").toString().replace("`n","").replace("`r","");
$url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-win64-msvc.zip";
}elseif($version -eq "beta") {
$latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST_BETA").toString().replace("`n","").replace("`r","");
$url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-win64-msvc.zip";
} else {
$latest = $version;
$url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-win64-msvc.zip";
}
$env:PATH += ";C:\ldc2-$($latest)-win64-msvc\bin";
$env:DC = "ldc2";
return $url;
}
- ps: function SetUpDCompiler
{
$env:toolchain = "msvc";
if($env:DC -eq "dmd"){
echo "downloading ...";
$url = ResolveLatestDMD;
echo $url;
Invoke-WebRequest $url -OutFile "c:\dmd.7z";
echo "finished.";
pushd c:\\;
7z x dmd.7z > $null;
popd;
}
elseif($env:DC -eq "ldc"){
echo "downloading ...";
$url = ResolveLatestLDC;
echo $url;
Invoke-WebRequest $url -OutFile "c:\ldc.zip";
echo "finished.";
pushd c:\\;
7z x ldc.zip > $null;
popd;
}
}
- ps: SetUpDCompiler
build_script:
- ps: if($env:arch -eq "x86"){
$env:compilersetupargs = "x86";
$env:Darch = "x86";
$env:DConf = "m32";
}elseif($env:arch -eq "x64"){
$env:compilersetupargs = "amd64";
$env:Darch = "x86_64";
$env:DConf = "m64";
}
- ps: $env:compilersetup = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall";
- '"%compilersetup%" %compilersetupargs%'
test_script:
- echo %PLATFORM%
- echo %Darch%
- echo %DC%
- echo %PATH%
- '%DC% --version'
- dub test --arch=%Darch% --compiler=%DC%
- git submodule update --init --recursive
- build.bat

View file

@ -24,7 +24,7 @@ _dfmt()
eolOpts="lf cr crlf"
boolOpts="true false"
braceOpts="allman otbs stroustrup"
braceOpts="allman otbs stroustrup knr"
indentOpts="tab space"
constraintOpts="conditional_newline_indent conditional_newline always_newline always_newline_indent"

View file

@ -4,7 +4,7 @@
"targetType": "autodetect",
"license": "BSL-1.0",
"dependencies": {
"libdparse": ">=0.14.0 <0.18.0"
"libdparse": ">=0.19.2 <1.0.0"
},
"targetPath" : "bin/",
"targetName" : "dfmt",
@ -14,7 +14,7 @@
"versions" : [
"built_with_dub"
],
"preGenerateCommands" : [
"rdmd \"$PACKAGE_DIR/dubhash.d\""
"preBuildCommands" : [
"$DC -run \"$PACKAGE_DIR/dubhash.d\""
]
}

@ -1 +1 @@
Subproject commit 9aefc9c5e6e1495aca094d5c403f35f1052677d1
Subproject commit fe6d1e38fb4fc04323170389cfec67ed7fd4e24a

View file

@ -1,53 +1,63 @@
PREFIX = /usr/local
SRC := $(shell find src -name "*.d") \
$(shell find libdparse/src -name "*.d") \
$(shell find stdx-allocator/source -name "*.d")
INCLUDE_PATHS := -Ilibdparse/src -Istdx-allocator/source -Isrc -Jbin
DMD_COMMON_FLAGS := -dip25 -w $(INCLUDE_PATHS)
DMD_DEBUG_FLAGS := -debug -g $(DMD_COMMON_FLAGS)
DMD_FLAGS := -O -inline $(DMD_COMMON_FLAGS)
DMD_TEST_FLAGS := -unittest -g $(DMD_COMMON_FLAGS)
LDC_FLAGS := -g -w -oq $(INCLUDE_PATHS)
GDC_FLAGS := -g -w -oq $(INCLUDE_PATHS)
override DMD_FLAGS += $(DFLAGS)
override LDC_FLAGS += $(DFLAGS)
override GDC_FLAGS += $(DFLAGS)
$(shell find libdparse/src -name "*.d")
IMPORTS := -Ilibdparse/src -Isrc -Jbin
DC ?= dmd
LDC ?= ldc2
GDC ?= gdc
.PHONY: dmd ldc gdc test
DMD_COMMON_FLAGS := -w $(IMPORTS)
DMD_DEBUG_FLAGS := -debug -g $(DMD_COMMON_FLAGS)
DMD_FLAGS := -O -inline $(DMD_COMMON_FLAGS)
DMD_TEST_FLAGS := -unittest -g $(DMD_COMMON_FLAGS)
LDC_FLAGS := -g -w -oq $(IMPORTS)
GDC_FLAGS := -g -w -oq $(IMPORTS)
override DMD_FLAGS += $(DFLAGS)
override LDC_FLAGS += $(DFLAGS)
override GDC_FLAGS += $(DFLAGS)
dmd: bin/dfmt
.PHONY: all clean install debug dmd ldc gdc pkg release test
githash:
all: bin/dfmt
bin/githash.txt:
mkdir -p bin
git describe --tags > bin/githash.txt
ldc: githash
dmd: bin/dfmt
ldc: bin/githash.txt
$(LDC) $(SRC) $(LDC_FLAGS) -ofbin/dfmt
-rm -f *.o
gdc:githash
gdc: bin/githash.txt
$(GDC) $(SRC) $(GDC_FLAGS) -obin/dfmt
test: debug
cd tests && ./test.sh
cd tests && ./test.d
bin/dfmt-test: githash $(SRC)
$(DC) $(DMD_TEST_FLAGS) $^ -of$@
bin/dfmt-test: bin/githash.txt $(SRC)
$(DC) $(DMD_TEST_FLAGS) $(filter %.d,$^) -of$@
bin/dfmt: githash $(SRC)
bin/dfmt: bin/githash.txt $(SRC)
$(DC) $(DMD_FLAGS) $(filter %.d,$^) -of$@
debug: githash $(SRC)
debug: bin/githash.txt $(SRC)
$(DC) $(DMD_DEBUG_FLAGS) $(filter %.d,$^) -ofbin/dfmt
pkg: dmd
$(MAKE) -f makd/Makd.mak pkg
clean:
$(RM) bin/dfmt
$(RM) bin/dfmt bin/dfmt-test bin/githash.txt
install:
chmod +x bin/dfmt
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f bin/dfmt $(DESTDIR)$(PREFIX)/bin/dfmt
release:
./release.sh
githash
$(MAKE) bin/githash.txt

View file

@ -63,6 +63,8 @@ struct ASTInformation
(structInfoSortedByEndLocation);
sort(ufcsHintLocations);
ufcsHintLocations = ufcsHintLocations.uniq().array();
sort(ternaryColonLocations);
sort(namedArgumentColonLocations);
}
/// Locations of end braces for struct bodies
@ -95,6 +97,12 @@ struct ASTInformation
/// Closing braces of function literals
size_t[] funLitEndLocations;
/// Locations of aggregate bodies (struct, class, union)
size_t[] aggregateBodyLocations;
/// Locations of function bodies
size_t[] funBodyLocations;
/// Conditional statements that have matching "else" statements
size_t[] conditionalWithElseLocations;
@ -129,6 +137,12 @@ struct ASTInformation
/// Opening & closing braces of struct initializers
StructInitializerInfo[] structInfoSortedByEndLocation;
/// Locations ternary expression colons.
size_t[] ternaryColonLocations;
/// Locations of named arguments of function call or struct constructor.
size_t[] namedArgumentColonLocations;
}
/// Collects information from the AST that is useful for the formatter
@ -200,6 +214,18 @@ final class FormatVisitor : ASTVisitor
destructor.accept(this);
}
override void visit (const FunctionBody functionBody)
{
if (auto bd = functionBody.specifiedFunctionBody)
{
if (bd.blockStatement)
{
astInformation.funBodyLocations ~= bd.blockStatement.startLocation;
}
}
functionBody.accept(this);
}
override void visit(const ConditionalDeclaration dec)
{
if (dec.hasElse)
@ -313,6 +339,7 @@ final class FormatVisitor : ASTVisitor
override void visit(const StructBody structBody)
{
astInformation.aggregateBodyLocations ~= structBody.startLocation;
astInformation.doubleNewlineLocations ~= structBody.endLocation;
structBody.accept(this);
}
@ -419,6 +446,43 @@ final class FormatVisitor : ASTVisitor
outStatement.accept(this);
}
override void visit(const TernaryExpression ternaryExpression)
{
astInformation.ternaryColonLocations ~= ternaryExpression.colon.index;
ternaryExpression.accept(this);
}
override void visit(const FunctionCallExpression functionCall)
{
// Check if function has any arguments.
if (functionCall.arguments.namedArgumentList is null)
{
functionCall.accept(this);
return;
}
foreach (item; functionCall.arguments.namedArgumentList.items)
{
// Do nothing if not a named argument.
if (item.name == tok!"")
{
continue;
}
// Find first colon if named argument.
foreach (t; item.tokens)
{
if (t.type == tok!":")
{
astInformation.namedArgumentColonLocations ~= t.index;
break;
}
}
}
functionCall.accept(this);
}
private:
ASTInformation* astInformation;
}

View file

@ -10,18 +10,20 @@ import dfmt.editorconfig;
/// Brace styles
enum BraceStyle
{
unspecified,
_unspecified,
/// $(LINK https://en.wikipedia.org/wiki/Indent_style#Allman_style)
allman,
/// $(LINK https://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS)
otbs,
/// $(LINK https://en.wikipedia.org/wiki/Indent_style#Variant:_Stroustrup)
stroustrup
stroustrup,
/// $(LINK https://en.wikipedia.org/wiki/Indentation_style#K&R_style)
knr,
}
enum TemplateConstraintStyle
{
unspecified,
_unspecified,
conditional_newline_indent,
conditional_newline,
always_newline,
@ -59,6 +61,14 @@ struct Config
OptionalBoolean dfmt_space_before_aa_colon;
///
OptionalBoolean dfmt_keep_line_breaks;
///
OptionalBoolean dfmt_single_indent;
///
OptionalBoolean dfmt_reflow_property_chains;
///
OptionalBoolean dfmt_space_after_statement_keyword;
///
OptionalBoolean dfmt_space_before_named_arg_colon;
mixin StandardEditorConfigFields;
@ -69,7 +79,7 @@ struct Config
void initializeWithDefaults()
{
pattern = "*.d";
end_of_line = EOL.lf;
end_of_line = EOL._default;
indent_style = IndentStyle.space;
indent_size = 4;
tab_width = 4;
@ -88,6 +98,9 @@ struct Config
dfmt_single_template_constraint_indent = OptionalBoolean.f;
dfmt_space_before_aa_colon = OptionalBoolean.f;
dfmt_keep_line_breaks = OptionalBoolean.f;
dfmt_single_indent = OptionalBoolean.f;
dfmt_reflow_property_chains = OptionalBoolean.t;
dfmt_space_before_named_arg_colon = OptionalBoolean.f;
}
/**

View file

@ -26,21 +26,22 @@ private auto commentRe = ctRegex!(`^\s*[#;].*$`);
enum OptionalBoolean : ubyte
{
unspecified = 3,
_unspecified = 3,
t = 1,
f = 0
}
enum IndentStyle : ubyte
{
unspecified,
_unspecified,
tab,
space
}
enum EOL : ubyte
{
unspecified,
_unspecified,
_default,
lf,
cr,
crlf
@ -74,7 +75,7 @@ mixin template StandardEditorConfigFields()
static if (N == "pattern")
continue;
else static if (is(T == enum))
*thisN = otherN != T.unspecified ? otherN : *thisN;
*thisN = otherN != T._unspecified ? otherN : *thisN;
else static if (is(T == int))
*thisN = otherN != -1 ? otherN : *thisN;
else static if (is(T == string))

View file

@ -15,6 +15,7 @@ import dfmt.indentation;
import dfmt.tokens;
import dfmt.wrapping;
import std.array;
import std.algorithm.comparison : among, max;
/**
* Formats the code contained in `buffer` into `output`.
@ -110,6 +111,7 @@ struct TokenFormatter(OutputRange)
this.output = output;
this.astInformation = astInformation;
this.config = config;
this.indents = IndentStack(config);
{
auto eol = config.end_of_line;
@ -119,8 +121,13 @@ struct TokenFormatter(OutputRange)
this.eolString = "\n";
else if (eol == eol.crlf)
this.eolString = "\r\n";
else if (eol == eol.unspecified)
else if (eol == eol._unspecified)
assert(false, "config.end_of_line was unspecified");
else
{
assert (eol == eol._default);
this.eolString = eolStringFromInput;
}
}
}
@ -194,6 +201,22 @@ private:
/// True if the next "else" should be formatted as a single line
bool inlineElse;
/// Tracks paren depth on a single line. This information can be used to
/// indent array literals inside parens, since arrays are indented only once
/// and paren indentation is ignored. Line breaks and "[" reset the counter.
int parenDepthOnLine;
string eolStringFromInput() const
{
import std.algorithm : countUntil;
// Intentional wraparound, -1 turns into uint.max when not found:
const firstCR = cast(uint) rawSource.countUntil("\r");
if (firstCR < cast(uint) rawSource.countUntil("\n"))
return firstCR == rawSource.countUntil("\r\n") ? "\r\n" : "\r";
return "\n";
}
void formatStep()
{
import std.range : assumeSorted;
@ -224,9 +247,9 @@ private:
else if (currentIs(tok!"return"))
{
writeToken();
if (!currentIs(tok!";") && !currentIs(tok!")") && !currentIs(tok!"{")
if (hasCurrent && (!currentIs(tok!";") && !currentIs(tok!")") && !currentIs(tok!"{")
&& !currentIs(tok!"in") && !currentIs(tok!"out") && !currentIs(tok!"do")
&& (hasCurrent && tokens[index].text != "body"))
&& tokens[index].text != "body"))
write(" ");
}
else if (currentIs(tok!"with"))
@ -234,16 +257,20 @@ private:
if (indents.length == 0 || !indents.topIsOneOf(tok!"switch", tok!"with"))
indents.push(tok!"with");
writeToken();
write(" ");
if (currentIs(tok!"("))
if (config.dfmt_space_after_keywords) {
write(" ");
}
if (hasCurrent && currentIs(tok!"("))
writeParens(false);
if (!currentIs(tok!"switch") && !currentIs(tok!"with")
if (hasCurrent && !currentIs(tok!"switch") && !currentIs(tok!"with")
&& !currentIs(tok!"{") && !(currentIs(tok!"final") && peekIs(tok!"switch")))
{
newline();
}
else if (!currentIs(tok!"{"))
else if (hasCurrent && !currentIs(tok!"{"))
{
write(" ");
}
}
else if (currentIs(tok!"switch"))
{
@ -274,6 +301,10 @@ private:
else
formatBlockHeader();
}
else if ((current.text == "body" || current == tok!"do") && peekBackIsFunctionDeclarationEnding())
{
formatKeyword();
}
else if (currentIs(tok!"do"))
{
formatBlockHeader();
@ -321,14 +352,10 @@ private:
inlineElse = true;
formatKeyword();
}
else if (current.text == "body" && peekBackIsFunctionDeclarationEnding())
{
formatKeyword();
}
else if (isBasicType(current.type))
{
writeToken();
if (currentIs(tok!"identifier") || isKeyword(current.type) || inAsm)
if (hasCurrent && (currentIs(tok!"identifier") || isKeyword(current.type) || inAsm))
write(" ");
}
else if (isOperator(current.type))
@ -369,7 +396,7 @@ private:
import dfmt.editorconfig : OB = OptionalBoolean;
with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style)
{
case unspecified:
case _unspecified:
assert(false, "Config was not validated properly");
case conditional_newline:
immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]);
@ -476,6 +503,9 @@ private:
if (peekIs(tok!"(") && (peekBackIs(tok!")") || peekBack2Is(tok!"!")))
pushWrapIndent(tok!"(");
if (peekIs(tok!".") && !indents.topIs(tok!"."))
indents.push(tok!".");
}
writeToken();
immutable j = justAddedExtraNewline;
@ -595,6 +625,7 @@ private:
writeToken();
if (p == tok!"(")
{
++parenDepthOnLine;
// If the file starts with an open paren, just give up. This isn't
// valid D code.
if (index < 2)
@ -612,23 +643,10 @@ private:
immutable bool arrayInitializerStart = p == tok!"["
&& astInformation.arrayStartLocations.canFindIndex(tokens[index - 1].index);
if (p == tok!"[" && config.dfmt_keep_line_breaks == OptionalBoolean.t)
if (arrayInitializerStart && isMultilineAt(index - 1))
{
IndentStack.Details detail;
revertParenIndentation();
detail.wrap = false;
detail.temp = false;
detail.breakEveryItem = false;
detail.mini = tokens[index].line == tokens[index - 1].line;
indents.push(tok!"]", detail);
if (!detail.mini)
{
newline();
}
}
else if (arrayInitializerStart && isMultilineAt(index - 1))
{
// Use the close bracket as the indent token to distinguish
// the array initialiazer from an array index in the newline
// handling code
@ -649,6 +667,22 @@ private:
linebreakHints = chooseLineBreakTokens(index, tokens[index .. j],
depths[index .. j], config, currentLineLength, indentLevel);
}
else if (p == tok!"[" && config.dfmt_keep_line_breaks == OptionalBoolean.t)
{
revertParenIndentation();
IndentStack.Details detail;
detail.wrap = false;
detail.temp = false;
detail.breakEveryItem = false;
detail.mini = tokens[index].line == tokens[index - 1].line;
indents.push(tok!"]", detail);
if (!detail.mini)
{
newline();
}
}
else if (arrayInitializerStart)
{
// This is a short (non-breaking) array/AA value
@ -688,6 +722,24 @@ private:
}
}
void revertParenIndentation()
{
import std.algorithm.searching : canFind, until;
if (tokens[index .. $].until!(tok => tok.line != current.line).canFind!(x => x.type == tok!"]"))
{
return;
}
if (parenDepthOnLine)
{
foreach (i; 0 .. parenDepthOnLine)
{
indents.pop();
}
}
parenDepthOnLine = 0;
}
void formatRightParen()
in
{
@ -695,12 +747,15 @@ private:
}
do
{
parenDepthOnLine = max(parenDepthOnLine - 1, 0);
parenDepth--;
indents.popWrapIndents();
while (indents.topIsOneOf(tok!"!", tok!")"))
indents.pop();
if (indents.topIs(tok!"("))
indents.pop();
if (indents.topIs(tok!"."))
indents.pop();
if (onNextLine)
{
@ -780,12 +835,13 @@ private:
{
import dfmt.editorconfig : OptionalBoolean;
import std.algorithm : canFind, any;
immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index);
immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex(
current.line);
immutable bool isStructInitializer = astInformation.structInfoSortedByEndLocation
.canFind!(st => st.startLocation < current.index && current.index < st.endLocation);
immutable bool isTernary = astInformation.ternaryColonLocations.canFindIndex(current.index);
immutable bool isNamedArg = astInformation.namedArgumentColonLocations.canFindIndex(current.index);
if (isCase || isAttribute)
{
@ -801,11 +857,17 @@ private:
newline();
}
}
else if (indents.topIs(tok!"]")) // Associative array
else if (indents.topIs(tok!"]") && !isTernary) // Associative array
{
write(config.dfmt_space_before_aa_colon ? " : " : ": ");
++index;
}
// Named function or struct constructor arguments.
else if (isNamedArg)
{
write(config.dfmt_space_before_named_arg_colon ? " : " : ": ");
++index;
}
else if (peekBackIs(tok!"identifier")
&& [tok!"{", tok!"}", tok!";", tok!":", tok!","]
.any!((ptrdiff_t token) => peekBack2Is(cast(IdType)token, true))
@ -963,6 +1025,10 @@ private:
if (config.dfmt_brace_style == BraceStyle.allman
|| peekBackIsOneOf(true, tok!"{", tok!"}"))
newline();
else if (config.dfmt_brace_style == BraceStyle.knr
&& astInformation.funBodyLocations.canFindIndex(tIndex)
&& (peekBackIs(tok!")") || (!peekBackIs(tok!"do") && peekBack().text != "body")))
newline();
else if (!peekBackIsOneOf(true, tok!"{", tok!"}", tok!";"))
write(" ");
writeToken();
@ -994,6 +1060,21 @@ private:
if (niBraceDepth > 0)
niBraceDepth--;
// Account for possible function literals in this array which offset
// the previously set index (pos). Fixes issue #432.
size_t newPos = pos;
while(astInformation.indentInfoSortedByEndLocation[newPos].endLocation <
tokens[index].index)
{
newPos++;
}
if (astInformation.indentInfoSortedByEndLocation[newPos].endLocation ==
tokens[index].index)
{
pos = newPos;
}
auto indentInfo = astInformation.indentInfoSortedByEndLocation[pos];
if (indentInfo.flags & BraceIndentInfoFlags.tempIndent)
{
@ -1031,7 +1112,7 @@ private:
currentLineLength = 0;
justAddedExtraNewline = true;
}
if (config.dfmt_brace_style == BraceStyle.otbs
if (config.dfmt_brace_style.among(BraceStyle.otbs, BraceStyle.knr)
&& ((peekIs(tok!"else")
&& !indents.topAre(tok!"static", tok!"if")
&& !indents.topIs(tok!"foreach") && !indents.topIs(tok!"for")
@ -1063,7 +1144,10 @@ private:
indents.pop();
indents.push(tok!"switch");
writeToken(); // switch
write(" ");
if (config.dfmt_space_after_keywords)
{
write(" ");
}
}
void formatBlockHeader()
@ -1094,16 +1178,26 @@ private:
if (currentIs(tok!"("))
{
write(" ");
if (config.dfmt_space_after_keywords)
{
write(" ");
}
writeParens(false);
}
if (hasCurrent)
{
if (currentIs(tok!"switch") || (currentIs(tok!"final") && peekIs(tok!"switch")))
write(" ");
{
if (config.dfmt_space_after_keywords)
{
write(" ");
}
}
else if (currentIs(tok!"comment"))
{
formatStep();
}
else if (!shouldPushIndent)
{
if (!currentIs(tok!"{") && !currentIs(tok!";"))
@ -1184,24 +1278,26 @@ private:
break;
case tok!"cast":
writeToken();
if (currentIs(tok!"("))
if (hasCurrent && currentIs(tok!"("))
writeParens(config.dfmt_space_after_cast == OptionalBoolean.t);
break;
case tok!"out":
if (!peekBackIs(tok!"}")
&& astInformation.contractLocations.canFindIndex(current.index))
newline();
else if (peekBackIsKeyword)
write(" ");
if (!peekBackIsSlashSlash) {
if (!peekBackIs(tok!"}")
&& astInformation.contractLocations.canFindIndex(current.index))
newline();
else if (peekBackIsKeyword)
write(" ");
}
writeToken();
if (!currentIs(tok!"{") && !currentIs(tok!"comment"))
if (hasCurrent && !currentIs(tok!"{") && !currentIs(tok!"comment"))
write(" ");
break;
case tok!"try":
case tok!"finally":
indents.push(current.type);
writeToken();
if (!currentIs(tok!"{"))
if (hasCurrent && !currentIs(tok!"{"))
newline();
break;
case tok!"identifier":
@ -1216,14 +1312,18 @@ private:
break;
case tok!"in":
immutable isContract = astInformation.contractLocations.canFindIndex(current.index);
if (isContract)
{
indents.popTempIndents();
newline();
if (!peekBackIsSlashSlash) {
if (isContract)
{
indents.popTempIndents();
newline();
}
else if (!peekBackIsOneOf(false, tok!"(", tok!",", tok!"!"))
write(" ");
}
else if (!peekBackIsOneOf(false, tok!"(", tok!",", tok!"!"))
write(" ");
writeToken();
if (!hasCurrent)
return;
immutable isFunctionLit = astInformation.funLitStartLocations.canFindIndex(
current.index);
if (isFunctionLit && config.dfmt_brace_style == BraceStyle.allman)
@ -1236,12 +1336,12 @@ private:
tok!"}", tok!"=", tok!"&&", tok!"||") && !peekBackIsKeyword())
write(" ");
writeToken();
if (!currentIs(tok!"(") && !currentIs(tok!"{") && !currentIs(tok!"comment"))
if (hasCurrent && !currentIs(tok!"(") && !currentIs(tok!"{") && !currentIs(tok!"comment"))
write(" ");
break;
case tok!"case":
writeToken();
if (!currentIs(tok!";"))
if (hasCurrent && !currentIs(tok!";"))
write(" ");
break;
case tok!"enum":
@ -1255,7 +1355,7 @@ private:
write(" ");
indents.push(tok!"enum");
writeToken();
if (!currentIs(tok!":") && !currentIs(tok!"{"))
if (hasCurrent && !currentIs(tok!":") && !currentIs(tok!"{"))
write(" ");
}
break;
@ -1279,7 +1379,7 @@ private:
goto default;
case tok!"invariant":
writeToken();
if (currentIs(tok!"("))
if (hasCurrent && currentIs(tok!"("))
write(" ");
break;
default:
@ -1403,11 +1503,13 @@ private:
break;
case tok!".":
regenLineBreakHintsIfNecessary(index);
immutable bool ufcsWrap = astInformation.ufcsHintLocations.canFindIndex(current.index);
immutable bool ufcsWrap = config.dfmt_reflow_property_chains == OptionalBoolean.t
&& astInformation.ufcsHintLocations.canFindIndex(current.index);
if (ufcsWrap || linebreakHints.canFind(index) || onNextLine
|| (linebreakHints.length == 0 && currentLineLength + nextTokenLength() > config.max_line_length))
{
pushWrapIndent();
if (!indents.topIs(tok!"."))
indents.push(tok!".");
if (!peekBackIs(tok!"comment"))
newline();
if (ufcsWrap || onNextLine)
@ -1571,6 +1673,10 @@ private:
const commaLine = tokens[index].line;
writeToken();
if (indents.topIsWrap && !indents.topIs(tok!","))
{
indents.pop;
}
if (!currentIs(tok!")") && !currentIs(tok!"]")
&& !currentIs(tok!"}") && !currentIs(tok!"comment"))
{
@ -1589,6 +1695,10 @@ private:
{
pushWrapIndent();
writeToken();
if (indents.topIsWrap && !indents.topIs(tok!","))
{
indents.pop;
}
newline();
}
else
@ -1765,7 +1875,19 @@ private:
if (indents.topIs(tok!"]"))
{
indents.pop();
indentLevel = indents.indentLevel;
}
// Find the initial indentation of constructs like "if" and
// "foreach" without removing them from the stack, since they
// still can be used later to indent "else".
auto savedIndents = IndentStack(config);
while (indents.length >= 0 && indents.topIsTemp) {
savedIndents.push(indents.top, indents.topDetails);
indents.pop;
}
indentLevel = indents.indentLevel;
while (savedIndents.length > 0) {
indents.push(savedIndents.top, savedIndents.topDetails);
savedIndents.pop;
}
}
else if (astInformation.attributeDeclarationLines.canFindIndex(current.line))
@ -1796,6 +1918,7 @@ private:
}
indent();
}
parenDepthOnLine = 0;
}
void write(string str)
@ -1808,6 +1931,8 @@ private:
{
import std.range:retro;
import std.algorithm.searching:countUntil;
import std.algorithm.iteration:joiner;
import std.string:lineSplitter;
if (current.text is null)
{
@ -1817,12 +1942,7 @@ private:
}
else
{
// You know what's awesome? Windows can't handle its own line
// endings correctly.
version (Windows)
output.put(current.text.replace("\r", ""));
else
output.put(current.text);
output.put(current.text.lineSplitter.joiner(eolString));
switch (current.type)
{
case tok!"stringLiteral":

View file

@ -12,7 +12,7 @@ import std.path : filenameCharCmp, isDirSeparator;
// * changes meaning to match all characters except '/'
// ** added to take over the old meaning of *
bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)(
Range path, const(C)[] pattern) @safe pure nothrow
Range path, const(C)[] pattern) @safe pure
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)
&& isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range)))
in

View file

@ -5,6 +5,8 @@
module dfmt.indentation;
import dfmt.config;
import dfmt.editorconfig;
import dparse.lexer;
import std.bitmanip : bitfields;
@ -31,6 +33,14 @@ bool isTempIndent(IdType type) pure nothrow @nogc @safe
*/
struct IndentStack
{
/// Configuration
private const Config* config;
this(const Config* config)
{
this.config = config;
}
static struct Details
{
mixin(bitfields!(
@ -221,7 +231,7 @@ struct IndentStack
/**
* Dumps the current state of the indentation stack to `stderr`. Used for debugging.
*/
void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__)
void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) const
{
import dparse.lexer : str;
import std.algorithm.iteration : map;
@ -260,8 +270,20 @@ private:
if (i + 1 < index)
{
if (config.dfmt_single_indent == OptionalBoolean.t && skipDoubleIndent(i, parenCount))
{
parenCount = pc;
continue;
}
immutable currentIsNonWrapTemp = !details[i].wrap
&& details[i].temp && arr[i] != tok!")" && arr[i] != tok!"!";
if (currentIsNonWrapTemp && arr[i + 1] == tok!"]")
{
parenCount = pc;
continue;
}
if (arr[i] == tok!"static"
&& arr[i + 1].among!(tok!"if", tok!"else", tok!"foreach", tok!"foreach_reverse")
&& (i + 2 >= index || arr[i + 2] != tok!"{"))
@ -276,7 +298,7 @@ private:
continue;
}
}
else if (parenCount == 0 && arr[i] == tok!"(")
else if (parenCount == 0 && arr[i] == tok!"(" && config.dfmt_single_indent == OptionalBoolean.f)
size++;
if (arr[i] == tok!"!")
@ -287,6 +309,12 @@ private:
}
return size;
}
bool skipDoubleIndent(size_t i, int parenCount) const pure nothrow @safe @nogc
{
return (details[i + 1].wrap && arr[i] == tok!")")
|| (parenCount == 0 && arr[i + 1] == tok!"," && arr[i] == tok!"(");
}
}
unittest

View file

@ -38,13 +38,13 @@ version (NoMain)
}
else
{
import std.array : front, popFront;
import std.stdio : stdout, stdin, stderr, writeln, File;
import dfmt.config : Config;
import dfmt.formatter : format;
import std.path : buildPath, dirName, expandTilde;
import dfmt.editorconfig : getConfigFor;
import dfmt.formatter : format;
import std.array : appender, front, popFront;
import std.getopt : getopt, GetOptException;
import std.path : buildPath, dirName, expandTilde;
import std.stdio : File, stderr, stdin, stdout, writeln;
int main(string[] args)
{
@ -92,9 +92,21 @@ else
case "space_before_aa_colon":
optConfig.dfmt_space_before_aa_colon = optVal;
break;
case "space_before_named_arg_colon":
optConfig.dfmt_space_before_named_arg_colon = optVal;
break;
case "keep_line_breaks":
optConfig.dfmt_keep_line_breaks = optVal;
break;
case "single_indent":
optConfig.dfmt_single_indent = optVal;
break;
case "reflow_property_chains":
optConfig.dfmt_reflow_property_chains = optVal;
break;
case "space_after_keywords":
optConfig.dfmt_space_after_keywords = optVal;
break;
default:
assert(false, "Invalid command-line switch");
}
@ -117,15 +129,19 @@ else
"soft_max_line_length", &optConfig.dfmt_soft_max_line_length,
"outdent_attributes", &handleBooleans,
"space_after_cast", &handleBooleans,
"space_after_keywords", &handleBooleans,
"selective_import_space", &handleBooleans,
"space_before_function_parameters", &handleBooleans,
"split_operator_at_line_end", &handleBooleans,
"compact_labeled_statements", &handleBooleans,
"single_template_constraint_indent", &handleBooleans,
"space_before_aa_colon", &handleBooleans,
"space_before_named_arg_colon", &handleBooleans,
"tab_width", &optConfig.tab_width,
"template_constraint_style", &optConfig.dfmt_template_constraint_style,
"keep_line_breaks", &handleBooleans);
"keep_line_breaks", &handleBooleans,
"single_indent", &handleBooleans,
"reflow_property_chains", &handleBooleans);
// dfmt on
}
catch (GetOptException e)
@ -149,14 +165,13 @@ else
args.popFront();
immutable bool readFromStdin = args.length == 0;
File output = stdout;
version (Windows)
{
// On Windows, set stdout to binary mode (needed for correct EOL writing)
// See Phobos' stdio.File.rawWrite
{
import std.stdio : _O_BINARY;
immutable fd = output.fileno;
immutable fd = stdout.fileno;
_setmode(fd, _O_BINARY);
version (CRuntime_DigitalMars)
{
@ -177,7 +192,7 @@ else
if (!exists(explicitConfigDir) || !isDir(explicitConfigDir))
{
stderr.writeln("--config_dir|c must specify existing directory path");
stderr.writeln("--config|c must specify existing directory path");
return 1;
}
explicitConfig = getConfigFor!Config(explicitConfigDir);
@ -216,7 +231,7 @@ else
break;
}
immutable bool formatSuccess = format("stdin", buffer,
output.lockingTextWriter(), &config);
stdout.lockingTextWriter(), &config);
return formatSuccess ? 0 : 1;
}
else
@ -258,10 +273,16 @@ else
{
buffer = new ubyte[](cast(size_t) f.size);
f.rawRead(buffer);
if (inplace)
output = File(path, "wb");
immutable bool formatSuccess = format(path, buffer, output.lockingTextWriter(), &config);
if (!formatSuccess)
auto output = appender!string;
immutable bool formatSuccess = format(path, buffer, output, &config);
if (formatSuccess)
{
if (inplace)
File(path, "wb").rawWrite(output.data);
else
stdout.rawWrite(output.data);
}
else
retVal = 1;
}
}
@ -285,12 +306,14 @@ private version (Windows)
template optionsToString(E) if (is(E == enum))
{
import std.algorithm.searching : startsWith;
enum optionsToString = () {
string result = "(";
foreach (s; [__traits(allMembers, E)])
{
if (s != "unspecified")
if (!s.startsWith("_"))
result ~= s ~ "|";
}
result = result[0 .. $ - 1] ~ ")";
@ -306,7 +329,7 @@ https://github.com/dlang-community/dfmt
Options:
--help, -h Print this help message
--inplace, -i Edit files in place
--config_dir, -c Path to directory to load .editorconfig file from.
--config, -c Path to directory to load .editorconfig file from.
--version Print the version number and then exit
Formatting Options:
@ -323,12 +346,16 @@ Formatting Options:
--outdent_attributes
--space_after_cast
--space_before_function_parameters
--space_after_keywords
--selective_import_space
--single_template_constraint_indent
--split_operator_at_line_end
--compact_labeled_statements
--template_constraint_style
--space_before_aa_colon
--space_before_named_arg_colon
--single_indent
--reflow_property_chains
`,
optionsToString!(typeof(Config.dfmt_template_constraint_style)));
}

View file

@ -0,0 +1,23 @@
class C
{
void f()
{
if (true)
{
f(map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map
.map.map.map.map.map.map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __FILE__, __LINE__);
g(map && map && map && map && map && map && map && map && map && map && map
&& map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __LINE__);
h(map || map || map || map || map || map || map || map || map || map || map
|| map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __LINE__);
i(map + map + map + map + map + map + map + map + map + map + map + map + map
+ map + map + map + map + map, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __LINE__);
}
}
}

View file

@ -0,0 +1,31 @@
class C
{
void f()
{
if (true)
{
f(
array.map!(a => a.prop)
.array
.to!string,
__FILE__,
__LINE__);
g(
map &&
map,
__FILE__,
__LINE__);
h(
map ||
map,
__FILE__,
__LINE__);
i(
map
+ map,
__FILE__,
__LINE__);
}
}
}

View file

@ -1,7 +1,7 @@
unittest
{
foo([
target.value.region[1], target.value.region[1],
target.value.region[1], target.value.region[1], target.value.region[1]
]);
target.value.region[1], target.value.region[1], target.value.region[1],
target.value.region[1], target.value.region[1]
]);
}

View file

@ -1,24 +1,24 @@
unittest
{
Bson base = Bson([
"maps": Bson([
Bson(["id": Bson(4), "comment": Bson("hello")]),
Bson(["id": Bson(49), "comment": Bson(null)])
]),
"short": Bson(["a": "b", "c": "d"]),
"numbers": Bson([
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
]),
"shuffleOnReset": serializeToBson([
"all": false,
"selected": true,
"maybe": false
]),
"resetOnEmpty": Bson(false),
"applyMods": Bson(true),
"sendComments": Bson(true)
]);
"maps": Bson([
Bson(["id": Bson(4), "comment": Bson("hello")]),
Bson(["id": Bson(49), "comment": Bson(null)])
]),
"short": Bson(["a": "b", "c": "d"]),
"numbers": Bson([
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 0
]),
"shuffleOnReset": serializeToBson([
"all": false,
"selected": true,
"maybe": false
]),
"resetOnEmpty": Bson(false),
"applyMods": Bson(true),
"sendComments": Bson(true)
]);
int[] x = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0

View file

@ -1,25 +1,25 @@
auto find()
{
return Map.findRange([
"$and": [
["deleted": Bson(false)],
[
"$or": Bson([
serializeToBson(["forceUpdate": Bson(true)]),
serializeToBson([
"info.approved": ["$eq": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 60.days))
]
]),
serializeToBson([
"info.approved": ["$ne": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 14.days))
]
])
])
]
"$and": [
["deleted": Bson(false)],
[
"$or": Bson([
serializeToBson(["forceUpdate": Bson(true)]),
serializeToBson([
"info.approved": ["$eq": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 60.days))
]
]),
serializeToBson([
"info.approved": ["$ne": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 14.days))
]
])
])
]
]);
]
]);
}

View file

@ -2,6 +2,6 @@ int /*sneaky*/ foo( /*comments*/ ) /*everywhere*/
{
// comment on its own line
foo() // comment on same line
.bar(); // also on same line
.bar(); // also on same line
/* again */ // same line
}

View file

@ -0,0 +1,54 @@
static foreach (x; [
1,
2,
3,
])
{
}
static foreach_reverse (x; [
1,
2,
3,
])
{
}
void f()
{
foreach (x; [
1,
2,
3,
])
{
}
foreach_reverse (x; [
1,
2,
3,
])
{
}
if (!SymbolTool.instance.workspacesFilesUris.canFind!sameFile(uri))
{
send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, [
]));
}
foreach (x; map([
1,
2,
3,
]))
{
}
foreach (x; foo!(map!([
1,
2,
3,
])))
{
}
}

View file

@ -0,0 +1 @@
alias u8 = ubyte

View file

@ -0,0 +1,8 @@
/* This test relies on ../.gitattributes to contain these lines:
tests/issue0228.d text eol=lf
tests/allman/issue0228.d.ref text eol=crlf
tests/knr/issue0228.d.ref text eol=crlf
tests/otbs/issue0228.d.ref text eol=crlf
*/

View file

@ -0,0 +1,40 @@
struct S1
{
ulong x;
ulong y;
ulong function(ulong) f;
}
struct S2
{
ulong x;
ulong y;
ulong z;
ulong w;
}
// -----------------------------------------------------------------------------
// Example 1
// Anonymous function in struct, long struct initializer
immutable S1 s1 = {
1111111111111111111, 1111111111111111111, (x) { return x + 1111; },
};
void f1()
{
}
// -----------------------------------------------------------------------------
// Example 2
// Anonymous function anywhere, long struct initializer
int function(int) f2 = (x) { return x + 1111; };
immutable S2 s = {
1111111111111111111, 1111111111111111111, 1111111111111111111, 1111111111111111111,
};
void f2()
{
}

View file

@ -0,0 +1,40 @@
class C
{
abstract void f1() //
in (true);
abstract void f2() /* */
in (true);
abstract bool f3() //
out (r; r);
abstract bool f4() /* */
out (r; r);
abstract void f5() //
do
{
}
abstract void f6() /* */
do
{
}
abstract bool f7() //
in (true) //
out (r; r) //
do //
{
return true;
}
abstract bool f8() /* */
in (true) /* */
out (r; r) /* */
do /* */
{
return true;
}
}

View file

@ -0,0 +1,29 @@
void main()
{
const a1 = [
builder.rebuild!((x, y, z) => x + y + z)
.rebuild!(x => x)
.rebuild!(x => x),
];
const a2 = [
builder.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
builder.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
];
foo([
line1,
value_line2_bla_bla_bla.propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c, d).propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c).value,
]);
}
void foo()
{
afdsafds.asdf.flub;
}

View file

@ -0,0 +1,74 @@
private void selectMember(Args...)(Args args)
{
static if (true)
{
static if (args[0])
{
}
else
{
}
}
if (true)
{
if (args[0])
{
}
else
{
}
}
}
private void selectMember(Args...)(Args args)
{
static if (true)
{
static if ([
0,
1,
2,
3,
4,
])
{
}
else
{
}
}
if (true)
{
if (args[
0,
1,
2,
3,
4,
])
{
}
else
{
}
}
}
void f()
{
foreach (x; y)
if (foo)
{
}
else
{
}
if (a)
if (b)
{
}
else
{
}
}

View file

@ -0,0 +1,34 @@
void main()
{
const a1 = [
builder
.rebuild!((x, y, z) => x + y + z)
.rebuild!(x => x)
.rebuild!(x => x),
];
const a2 = [
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
];
foo([
line1,
value_line2_bla_bla_bla.propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c, d).propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c).value,
]);
}
void foo()
{
afdsafds
.asdf
.flub;
}

View file

@ -0,0 +1,15 @@
string f()
{
return duration.total!"seconds".to!string;
}
string g()
{
return duration.total!"seconds"().to!string;
}
string h()
{
return duration.total!"seconds"().to!string.to!string.to!string.to!string.to!string.to!string
.to!string.to!string.to!string;
}

View file

@ -0,0 +1,4 @@
void f() return
do
{
}

View file

@ -0,0 +1 @@
/// Testing CR line endings. void main() { }

View file

@ -0,0 +1,4 @@
/// Testing CRLF line endings.
void main()
{
}

View file

@ -0,0 +1,4 @@
/// Testing LF line endings.
void main()
{
}

View file

@ -0,0 +1,8 @@
void f()
{
auto t = true ? 1 : 0;
auto a = [true ? 1 : 0];
auto aa1 = [0: true ? 1 : 0];
auto aa2 = [0: true ? (false ? 1 : 2) : 3];
auto aa3 = [0: true ? false ? 1 : 2 : 3];
}

View file

@ -0,0 +1,28 @@
void temp(int v1, int v2)
{
}
int f(int i)
{
return i;
}
struct S
{
int i;
int j;
}
void main()
{
temp(v1: 1, v2: 2);
temp(v1: 1, v2: 2,);
auto s = S(5, j: 3);
temp(v1: 1, v2: f(i: 2));
temp(v1: true ? i : false ? 2 : f(i: 3), v2: 4);
temp(v1: () { S s = S(i: 5); return s.i; }, v2: 1);
}

View file

@ -0,0 +1,11 @@
unittest
{
f([
x
]);
}
void f(T[] x,
const U y)
{
}

View file

@ -0,0 +1,7 @@
unittest
{
functionLengthDoesMatter([
firstFunctionInChain("A").seconFunctionInChain("B").value,
firstFunctionInChain("A").seconFunctionInChain("B").value
]);
}

View file

@ -0,0 +1,49 @@
unittest
{
{
bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo,
Three charlie, double delta)
{
if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo
&& foxtrot && golf && hotel && india && juliet)
{
}
}
}
}
void f()
{
string a = "foo"
~ "bar" /* bar */
~ "baz";
}
unittest
{
if (a)
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else")))
a();
}
}
unittest
{
callFunc({ int i = 10; return i; });
callFunc({
int i = 10;
foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo);
doStuff(withThings, andOtherStuff);
return i;
});
callFunc({
int i = 10;
foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName,
echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName);
doStuff(withThings, andOtherStuff);
return i;
}, more_stuff);
}

View file

@ -0,0 +1,41 @@
unittest
{
{
bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo,
Three charlie, double delta)
{
if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo
&& foxtrot && golf && hotel && india && juliet)
{
}
}
}
}
unittest
{
if (a)
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version") || !peekIs(tok!"else")))
a();
}
}
unittest
{
callFunc({ int i = 10; return i; });
callFunc({
int i = 10;
foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo);
doStuff(withThings, andOtherStuff);
return i;
});
callFunc({
int i = 10;
foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName,
echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName);
doStuff(withThings, andOtherStuff);
return i;
}, more_stuff);
}

View file

@ -0,0 +1,15 @@
void main(string[] args)
{
for(int i = 0; i < 10; ++i)
{
if(i == 9)
break;
}
while(false)
{
}
foreach(i; 0 .. 9)
{
}
}

View file

@ -0,0 +1 @@
--single_indent=true

View file

@ -0,0 +1,60 @@
class C
{
void f()
{
if (true)
{
f(
map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__LINE__);
g(
map && map && map && map && map && map && map && map && map && map && map && map,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__LINE__);
h(
map || map || map || map || map || map || map || map || map || map || map || map,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__LINE__);
i(
map + map + map + map + map + map + map + map + map + map + map + map + map + map + map + map + map
+ map,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__FILE__,
__LINE__);
}
}
}

View file

@ -0,0 +1,2 @@
--single_indent=true
--keep_line_breaks=true

View file

@ -0,0 +1,31 @@
class C
{
void f()
{
if (true)
{
f(
array.map!(a => a.prop)
.array
.to!string,
__FILE__,
__LINE__);
g(
map &&
map,
__FILE__,
__LINE__);
h(
map ||
map,
__FILE__,
__LINE__);
i(
map
+ map,
__FILE__,
__LINE__);
}
}
}

View file

@ -0,0 +1 @@
### This file should not be erased just because it is not formatted correctly

1
tests/foreach_array.args Normal file
View file

@ -0,0 +1 @@
--keep_line_breaks true

53
tests/foreach_array.d Normal file
View file

@ -0,0 +1,53 @@
static foreach (x; [
1,
2,
3,
])
{
}
static foreach_reverse (x; [
1,
2,
3,
])
{
}
void f()
{
foreach (x; [
1,
2,
3,
])
{
}
foreach_reverse (x; [
1,
2,
3,
])
{
}
if (!SymbolTool.instance.workspacesFilesUris.canFind!sameFile(uri))
{
send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, []));
}
foreach (x; map([
1,
2,
3,
]))
{
}
foreach (x; foo!(map!([
1,
2,
3,
])))
{
}
}

1
tests/incomplete_alias.d Normal file
View file

@ -0,0 +1 @@
alias u8 = ubyte

1
tests/issue0228.args Normal file
View file

@ -0,0 +1 @@
--end_of_line=crlf

8
tests/issue0228.d Normal file
View file

@ -0,0 +1,8 @@
/* This test relies on ../.gitattributes to contain these lines:
tests/issue0228.d text eol=lf
tests/allman/issue0228.d.ref text eol=crlf
tests/knr/issue0228.d.ref text eol=crlf
tests/otbs/issue0228.d.ref text eol=crlf
*/

38
tests/issue0432.d Normal file
View file

@ -0,0 +1,38 @@
struct S1
{
ulong x;
ulong y;
ulong function(ulong)f;
}
struct S2
{
ulong x;
ulong y;
ulong z;
ulong w;
}
// -----------------------------------------------------------------------------
// Example 1
// Anonymous function in struct, long struct initializer
immutable S1 s1 = {
1111111111111111111, 1111111111111111111, (x) { return x + 1111; },};
void f1()
{
}
// -----------------------------------------------------------------------------
// Example 2
// Anonymous function anywhere, long struct initializer
int function(int) f2 = (x) { return x + 1111; };
immutable S2 s = {
1111111111111111111, 1111111111111111111, 1111111111111111111, 1111111111111111111,};
void f2()
{
}

40
tests/issue0451.d Normal file
View file

@ -0,0 +1,40 @@
class C
{
abstract void f1() //
in (true);
abstract void f2() /* */
in (true);
abstract bool f3() //
out (r; r);
abstract bool f4() /* */
out (r; r);
abstract void f5() //
do
{
}
abstract void f6() /* */
do
{
}
abstract bool f7() //
in (true) //
out (r; r) //
do //
{
return true;
}
abstract bool f8() /* */
in (true) /* */
out (r; r) /* */
do /* */
{
return true;
}
}

33
tests/issue0494.d Normal file
View file

@ -0,0 +1,33 @@
void main()
{
const a1 = [
builder
.rebuild!((x, y, z) => x + y + z)
.rebuild!(x => x)
.rebuild!(x => x),
];
const a2 = [
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
];
foo([
line1,
value_line2_bla_bla_bla.propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c, d).propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c).value,
]);
}
void foo() {
afdsafds
.asdf
.flub;
}

View file

@ -0,0 +1 @@
--keep_line_breaks=true

74
tests/issue0494_else.d Normal file
View file

@ -0,0 +1,74 @@
private void selectMember(Args...)(Args args)
{
static if (true)
{
static if (args[0])
{
}
else
{
}
}
if (true)
{
if (args[0])
{
}
else
{
}
}
}
private void selectMember(Args...)(Args args)
{
static if (true)
{
static if ([
0,
1,
2,
3,
4,
])
{
}
else
{
}
}
if (true)
{
if (args[
0,
1,
2,
3,
4,
])
{
}
else
{
}
}
}
void f()
{
foreach (x; y)
if (foo)
{
}
else
{
}
if (a)
if (b)
{
}
else
{
}
}

View file

@ -0,0 +1 @@
--keep_line_breaks=true

View file

@ -0,0 +1,33 @@
void main()
{
const a1 = [
builder
.rebuild!((x, y, z) => x + y + z)
.rebuild!(x => x)
.rebuild!(x => x),
];
const a2 = [
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
builder
.rebuild!(x => x)
.rebuild!(x => x)
.rebuild!(x => x),
];
foo([
line1,
value_line2_bla_bla_bla.propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c, d).propertyCallBlaBlaBla(a, b, c)
.propertyCallBlaBlaBla(a, b, c).value,
]);
}
void foo() {
afdsafds
.asdf
.flub;
}

1
tests/issue0503.args Normal file
View file

@ -0,0 +1 @@
--reflow_property_chains=false

14
tests/issue0503.d Normal file
View file

@ -0,0 +1,14 @@
string f()
{
return duration.total!"seconds".to!string;
}
string g()
{
return duration.total!"seconds"().to!string;
}
string h()
{
return duration.total!"seconds"().to!string.to!string.to!string.to!string.to!string.to!string.to!string.to!string.to!string;
}

4
tests/issue0528.d Normal file
View file

@ -0,0 +1,4 @@
void f() return
do
{
}

1
tests/issue0552_cr.d Normal file
View file

@ -0,0 +1 @@
/// Testing CR line endings. void main() { }

4
tests/issue0552_crlf.d Normal file
View file

@ -0,0 +1,4 @@
/// Testing CRLF line endings.
void main()
{
}

4
tests/issue0552_lf.d Normal file
View file

@ -0,0 +1,4 @@
/// Testing LF line endings.
void main()
{
}

8
tests/issue0578.d Normal file
View file

@ -0,0 +1,8 @@
void f()
{
auto t = true ? 1 : 0;
auto a = [true ? 1: 0];
auto aa1 = [0: true ? 1: 0];
auto aa2 = [0: true ? (false ? 1: 2): 3];
auto aa3 = [0: true ? false ? 1: 2: 3];
}

31
tests/issue0586.d Normal file
View file

@ -0,0 +1,31 @@
void temp(int v1, int v2)
{
}
int f(int i)
{
return i;
}
struct S
{
int i;
int j;
}
void main()
{
temp(v1: 1, v2: 2);
temp(
v1: 1,
v2: 2,
);
auto s = S(5, j: 3);
temp(v1: 1, v2: f(i: 2));
temp(v1: true ? i : false ? 2 : f(i: 3), v2: 4);
temp(v1: () { S s = S(i: 5); return s.i; }, v2: 1);
}

View file

@ -0,0 +1 @@
--keep_line_breaks=true

View file

@ -0,0 +1,11 @@
unittest
{
f([
x
]);
}
void f(T[] x,
const U y)
{
}

View file

@ -0,0 +1 @@
--keep_line_breaks=true

View file

@ -0,0 +1,7 @@
unittest
{
functionLengthDoesMatter([
firstFunctionInChain("A").seconFunctionInChain("B").value,
firstFunctionInChain("A").seconFunctionInChain("B").value
]);
}

View file

@ -0,0 +1,2 @@
--single_indent true
--keep_line_breaks true

View file

@ -0,0 +1,49 @@
unittest
{
{
bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo,
Three charlie, double delta)
{
if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo
&& foxtrot && golf && hotel && india && juliet)
{
}
}
}
}
void f()
{
string a = "foo"
~ "bar" /* bar */
~ "baz";
}
unittest
{
if (a)
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else")))
a();
}
}
unittest
{
callFunc({ int i = 10; return i; });
callFunc({
int i = 10;
foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo);
doStuff(withThings, andOtherStuff);
return i;
});
callFunc({
int i = 10;
foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName,
echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName);
doStuff(withThings, andOtherStuff);
return i;
}, more_stuff);
}

0
tests/knr/.d.ref Normal file
View file

37
tests/knr/2d_arrays.d.ref Normal file
View file

@ -0,0 +1,37 @@
unittest {
targets = [
[
RectangleShape.create(tex, vec2(-8 * scale, -32 * scale),
vec2(16 * scale, 48 * scale), vec4(14 / 16.0, 0, 16 / 16.0, 3 / 16.0)),
RectangleShape.create(tex, vec2(-8 * scale, -32 * scale),
vec2(16 * scale, 32 * scale), vec4(14 / 16.0, 3 / 16.0, 16 / 16.0, 5 / 16.0))
],
[
RectangleShape.create(tex, vec2(-8 * scale, -8 * scale),
vec2(16 * scale, 16 * scale), vec4(14 / 16.0, 5 / 16.0, 15 / 16.0, 6 / 16.0)),
RectangleShape.create(tex, vec2(-8 * scale, -8 * scale),
vec2(16 * scale, 16 * scale), vec4(15 / 16.0, 5 / 16.0, 16 / 16.0, 6 / 16.0))
]
];
int[][] foo = [
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
],
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
]
];
float[3][3] mat = [
[234.3456, 42435.8653, 23.5], [3.245, 235.3, 234.664],
[14324.6453, 23434.645, 9678.345]
];
}
string[][] globalArray = [
["123456789012345678901234567890", "123456789012345678901234567890"],
["123456789012345678901234567890", "123456789012345678901234567890"]
];

View file

@ -0,0 +1,15 @@
import std.stdio;
class Foo {
}
import std.conv;
void main()
{
return;
}
const baz = 11;
class Foo2 : Foo {
}

View file

@ -0,0 +1,21 @@
class C {
void f()
{
if (true) {
f(map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map
.map.map.map.map.map.map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __FILE__, __LINE__);
g(map && map && map && map && map && map && map && map && map && map && map
&& map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __LINE__);
h(map || map || map || map || map || map || map || map || map || map || map
|| map, __FILE__, __FILE__, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __LINE__);
i(map + map + map + map + map + map + map + map + map + map + map + map + map
+ map + map + map + map + map, __FILE__, __FILE__, __FILE__,
__FILE__, __FILE__, __FILE__, __FILE__, __LINE__);
}
}
}

View file

@ -0,0 +1,29 @@
class C {
void f()
{
if (true) {
f(
array.map!(a => a.prop)
.array
.to!string,
__FILE__,
__LINE__);
g(
map &&
map,
__FILE__,
__LINE__);
h(
map ||
map,
__FILE__,
__LINE__);
i(
map
+ map,
__FILE__,
__LINE__);
}
}
}

View file

@ -0,0 +1,6 @@
unittest {
foo([
target.value.region[1], target.value.region[1], target.value.region[1],
target.value.region[1], target.value.region[1]
]);
}

View file

@ -0,0 +1,8 @@
void main()
{
string key;
int[string] var = [
key: 5
];
}

View file

@ -0,0 +1,25 @@
unittest {
Bson base = Bson([
"maps": Bson([
Bson(["id": Bson(4), "comment": Bson("hello")]),
Bson(["id": Bson(49), "comment": Bson(null)])
]),
"short": Bson(["a": "b", "c": "d"]),
"numbers": Bson([
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 0
]),
"shuffleOnReset": serializeToBson([
"all": false,
"selected": true,
"maybe": false
]),
"resetOnEmpty": Bson(false),
"applyMods": Bson(true),
"sendComments": Bson(true)
]);
int[] x = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
];
}

View file

@ -0,0 +1,25 @@
auto find()
{
return Map.findRange([
"$and": [
["deleted": Bson(false)],
[
"$or": Bson([
serializeToBson(["forceUpdate": Bson(true)]),
serializeToBson([
"info.approved": ["$eq": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 60.days))
]
]),
serializeToBson([
"info.approved": ["$ne": Bson(1)],
"fetchDate": [
"$lte": Bson(BsonDate(currentTime - 14.days))
]
])
])
]
]
]);
}

View file

@ -0,0 +1,13 @@
struct SomeStructName {
static struct InnerStruct {
version (linux) {
static if (condition) {
void longFunctionName(AAAAAAAA)(AAAAAAAA a) @property
if (someThingsAreTrue!AAAAAAAA && long_condition
&& is(elaborate == expression))
{
}
}
}
}
}

View file

@ -0,0 +1,13 @@
unittest {
{
{
foreach (abcde, def; abcdef.map!(battlecruiser => battlecruiser[123 .. 1231231])
.filter!(bravo => charlie[10] > 90000)
.sum()) {
}
abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234)
.abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234);
}
}
}

View file

@ -0,0 +1,41 @@
class U0 : Exception {
this() @safe pure nothrow
{
super("U0 error message");
}
}
class U1 : Exception {
this() @safe pure nothrow
{
super("U1 error message");
}
}
void foo()
{
import std.stdio;
foreach (immutable i; 0 .. 2) {
try {
i.bar;
} catch (U0) {
"Function foo caught exception U0".writeln;
}
}
}
void bar(in int i) @safe pure
{
i.baz;
}
void baz(in int i) @safe pure
{
throw i ? new U1 : new U0;
}
void main()
{
foo;
}

7
tests/knr/comments.d.ref Normal file
View file

@ -0,0 +1,7 @@
int /*sneaky*/ foo( /*comments*/ ) /*everywhere*/
{
// comment on its own line
foo() // comment on same line
.bar(); // also on same line
/* again */ // same line
}

View file

@ -0,0 +1,9 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales)
{
}
void foo()() if (dogs && pigs && birds)
{
}

View file

@ -0,0 +1,10 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales)
{
}
void foo()()
if (dogs && pigs && birds)
{
}

17
tests/knr/contracts.d.ref Normal file
View file

@ -0,0 +1,17 @@
void main(string[] args)
{
struct SomeStruct {
private:
int a;
int b;
void doStuff(int q)
in {
assert(q);
}
out (result) {
}
body {
writeln(q);
}
}
}

View file

@ -0,0 +1,7 @@
void main()
{
if (true)
debug {
foo();
}
}

View file

@ -0,0 +1,7 @@
void main()
{
debug (0)
foo();
else
bar();
}

18
tests/knr/dip1009.d.ref Normal file
View file

@ -0,0 +1,18 @@
int foo(int arg)
in {
assert(arg > 0);
}
out (result) {
assert(result == 0);
}
do {
return 0;
}
int bar(int arg)
in (arg > 0)
out (; true)
out /*Major*/ ( /*Tom*/ result /*To ground control*/ ; result == 0)
{
return 0;
}

15
tests/knr/do_body.d.ref Normal file
View file

@ -0,0 +1,15 @@
import character.body;
void body() @nogc
in {
}
body {
body = null;
}
void body()
in {
}
do {
body = null;
}

0
tests/knr/empty.d.ref Normal file
View file

View file

@ -0,0 +1,5 @@
enum Foo {
deprecated member0,
@UDA(0) member1
}

View file

@ -0,0 +1,47 @@
static foreach (x; [
1,
2,
3,
]) {
}
static foreach_reverse (x; [
1,
2,
3,
]) {
}
void f()
{
foreach (x; [
1,
2,
3,
]) {
}
foreach_reverse (x; [
1,
2,
3,
]) {
}
if (!SymbolTool.instance.workspacesFilesUris.canFind!sameFile(uri)) {
send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, [
]));
}
foreach (x; map([
1,
2,
3,
])) {
}
foreach (x; foo!(map!([
1,
2,
3,
]))) {
}
}

13
tests/knr/frontpage.d.ref Normal file
View file

@ -0,0 +1,13 @@
// Computes average line length for standard input.
import std.stdio;
void main()
{
ulong lines = 0;
double sumLength = 0;
foreach (line; stdin.byLine()) {
++lines;
sumLength += line.length;
}
writeln("Average line length: ", lines ? sumLength / lines : 0);
}

View file

@ -0,0 +1 @@
void foo(@UDA(0) @UDA(1) Bar bar);

View file

@ -0,0 +1,30 @@
import std.stdio, std.random, std.typecons, std.conv, std.string, std.range;
void main()
{
immutable interval = tuple(1, 100);
writefln("Guess my target number that is between " ~ "%d and %d (inclusive).\n", interval[]);
immutable target = uniform!"[]"(interval[]);
foreach (immutable i; sequence!q{n}) {
writef("Your guess #%d: ", i + 1);
immutable txt = stdin.readln.strip;
Nullable!int answer;
try {
answer = txt.to!int;
} catch (ConvException e) {
writefln(" I don't understand your input '%s'", txt);
continue;
}
if (answer < interval[0] || answer > interval[1]) {
writeln(" Out of range!");
continue;
}
if (answer == target) {
writeln(" Well guessed.");
break;
}
writeln(answer < target ? " Too low." : " Too high.");
}
}

Some files were not shown because too many files have changed in this diff Show more