Skip to content

Sync sketch formatter configuration from source #1285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 8, 2022
Merged

Sync sketch formatter configuration from source #1285

merged 3 commits into from
Aug 8, 2022

Conversation

per1234
Copy link
Contributor

@per1234 per1234 commented Aug 4, 2022

The Arduino IDE's "Auto Format" feature is configured to produce the standard Arduino sketch formatting style, as established by the Arduino IDE 1.x formatter.

The configuration is consumed by several other projects which require the configuration in a YAML file. In order to provide all the consumers with a single canonical source and to locate the infrastructure and activity related to the maintenance of the file in a more appropriate repository, it is now hosted in a permanent location in the arduino/tooling-project-assets repository:

https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration

The following changes have been made to the source configuration:

This last item did result in some functional changes to the configuration which will result in minor differences in the formatter output.

These are actually reversions of unwanted differences from the Arduino IDE 1.x formatter output, which were unavoidable when using the 11.0.1 version of ClangFormat in use at the time of the configuration's creation. These changes will provide greater consistency during the migration from Arduino IDE 1.x to 2.x. The default output of the Arduino IDE 1.x formatter will continue to be considered the "gold standard" until Arduino IDE 2.x graduates from "pre-release" status.

The Arduino IDE 2.x formatter configuration is fully customizable according to the preferences of each user:

https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-customize-auto-formatter

Those already using custom configurations will not be affected in any way (though they are encouraged to sync their configuration files from the source to bring them into compliance with the configuration API of the ClangFormat version currently in use by Arduino IDE 2.x).

See the documentation and commit history for the source file for details on the configuration changes:

https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration

Resolves #42

Required updates to configuration escaping code

The formatter configuration is passed to the ClangFormat tool as a string representation of a JSON object via a --style=<configuration>command line argument. Since it passes through the command line, this argument must be correctly quoted and escaped.

I discovered that, although it happened to work for the content of the previous configuration, the code that processed the argument string was insufficient to handle any arbitrary valid configuration content, and produced an invalid command from the updated configuration content.

This more minimal configuration effectively demonstrates the problem:

{
  SortIncludes: 'CaseSensitive',
  IncludeCategories: [
    {
      Regex: '^(<|")ba(r|z)',
      Priority: 9,
    },
  ],
}

(This causes #include directives matching the regular expression ^(<|")ba(r|z) to be sorted after others)

POSIX escaping

Quotes in the argument content must be backslash escaped in order to cause them to be treated as normal characters by POSIX shell command interpreters. The previous escaping code used by the Arduino IDE assumed that all quotes were from the JSON syntax. We see from the example configuration above that this is not a safe assumption. The configuration content itself might contain quote characters. With the previous escaping code, these would be converted to \\", whereas the correct escaping would look like \\\".

The previous escaping would produce the following command and error when ran on Linux and macOS:

$ clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^(<|\\")ba(r|z)\",\"Priority\":9}]}" foo.cpp
bash: syntax error near unexpected token `)'

A small modification to the replace method arguments provides the correct handling of quotes and any other escaped characters in the configuration content, producing this command:

clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^(<|\\\")ba(r|z)\",\"Priority\":9}]}"

Escaping for Windows command interpreter

The command produced at the end of the previous section is perfectly valid for use with the POSIX shell command interpreters of Linux or macOS. Unfortunately this is not the case for the Windows command interpreter:

> clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^(<|\\\")ba(r|z)\",\"Priority\":9}]}" foo.cpp
| was unexpected at this time.

| is a special character in the Windows command interpreter. This is not a problem when it is quoted. At first glance, it would appear that it is quoted in this command, but it is not. The reason is that the Windows command interpreter does not use the POSIX style backslash escaping. For this reason, backslash escaped quotes (\") in the argument are recognized as normal quotes. This means that, as far as the Windows command interpreter is concerned, the argument is alternating between quoted and unquoted states at random:

image

(Green highlighted characters are quoted, yellow highlighted characters are unquoted)

If any characters with special significance to the Windows command interpreter (e.g., <, >, ^, |) happen to occur in the unquoted segments, the command produces an error.

The caret character (^) is used for escaping by the Windows command interpreter. A naive approach would be to simply caret escape all special characters in the argument, producing this command:

> clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^^(^<^|\\\")ba(r^|z)\",\"Priority\":9}]}" foo.cpp

However, these added carets are only normal characters in the quoted segments. The problem can be seen in the effective configuration dumped by ClangFormat:

> clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^^(^<^|\\\")ba(r^|z)\",\"Priority\":9}]}" --dump-config

[...]

IncludeCategories:
  - Regex:           '^(<|")ba(r^|z)'

[...]

(Note that an unexpected ^ was introduced to the regular expression)

So the caret escaping code must only treat the unquoted segments, which occur after every other quote in the string. This finally produces a valid command for use on Windows machines:

> clang-format --style="{\"SortIncludes\":\"CaseSensitive\",\"IncludeCategories\":[{\"Regex\":\"^^(^<^|\\\")ba(r|z)\",\"Priority\":9}]}" foo.cpp

POSIX shell command interpreters don't know anything about Microsoft's caret escaping nonsense, so this must only be applied when running the formatting command on a Windows machine.

Reviewer checklist

  • PR addresses a single concern.
  • The PR has no duplicates (please search among the Pull Requests before creating one)
  • PR title and description are properly filled.
  • Docs have been added / updated (for bug fixes / features)

per1234 added 3 commits August 2, 2022 22:11
The sketch code formatter configuration is passed to the ClangFormat tool as a string representing a JSON object via a
command line argument.

The quotes in the JSON syntax are escaped in order to make them compatible with this usage. Previously, consideration
was not given to escaping of the content. For example, with the previous escaping code, this content: `\"` would be
converted to `\\"`, whereas the correct escaping would look like `\\\"`.

That did not result in problems only because the configuration didn't contain escaped content. This good fortune will
not persist through updates to the configuration so the command must be properly processed.

The content of the configuration will now be escaped in addition to the quotes of the JSON data format.
The sketch code formatter configuration is passed to the ClangFormat tool as a string representing a JSON object via a
command line argument.

Previously, the contents of this string were not given any special treatment to ensure compatibility with the command
interpreter used on Windows machines. That did not result in problems only because the configuration didn't contain
problematic combinations of characters. This good fortune will not persist through updates to the configuration, so the
command must be properly processed.

The Windows command interpreter does not use the POSIX style backslash escaping. For this reason, escaped quotes in the
argument are recognized as normal quotes, meaning that the string alternates between quoted and unquoted states at
random. When a character with special significance to the Windows command interpreter happens to occur outside a quoted
section, an error results.

The solution is to use the Windows command interpreter's caret escaping on these characters. Since such an escaping
system is not recognized by POSIX shells, this is only done when the application is running on a Windows machine.

References:

- https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/echo#remarks
- https://en.wikipedia.org/wiki/Escape_character#Windows_Command_Prompt
The Arduino IDE's "Auto Format" feature is configured to produce the standard Arduino sketch formatting style, as
established by the Arduino IDE 1.x formatter.

The configuration is consumed by several other projects which require the configuration in a YAML file. In order to
provide all the consumers with a single canonical source and to locate the infrastructure and activity related to the
maintenance of the file in a more appropriate repository, it is now hosted in a permanent location in the
`arduino/tooling-project-assets` repository.

The following changes have been made to the source configuration:

- Move documentation comments to a dedicated file in the upstream repository
- Make additional non-functional changes to the configuration format to facilitate maintenance
- Update to use the configuration API of ClangFormat 14.0.0

This last item did result in some functional changes to the configuration which will result in minor differences in the
formatter output.

These are actually reversions of unwanted differences from the Arduino IDE 1.x formatter output, which were unavoidable
when using the 11.0.1 version of ClangFormat in use at the time of the configuration's creation. These changes will
provide greater consistency during the migration from Arduino IDE 1.x to 2.x. The default output of the Arduino IDE
1.x formatter will continue to be considered the "gold standard" until Arduino IDE 2.x graduates from "pre-release"
status.

The Arduino IDE 2.x formatter configuration is fully customizable according to the preferences of each user. Those
already using custom configurations will not be affected in any way (though they are encouraged to sync their
configuration files from the source to bring them into compliance with the configuration API of the ClangFormat version
currently in use by Arduino IDE 2.x).

See the documentation and commit history for the source file for details on the configuration changes:

https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration
@per1234 per1234 added type: enhancement Proposed improvement topic: infrastructure Related to project infrastructure topic: code Related to content of the project itself labels Aug 4, 2022
@per1234 per1234 requested a review from kittaakos August 4, 2022 07:19
@per1234 per1234 self-assigned this Aug 4, 2022
Copy link
Contributor

@kittaakos kittaakos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the great work and the detailed change description, Per!

Is there a concrete example you want me to verify? One thing that came to my mind; checking the escaping when starting the IDE2 on Windows from CMD.exe, PowerShell, and GitBash.

@per1234
Copy link
Contributor Author

per1234 commented Aug 4, 2022

Is there a concrete example you want me to verify?

There is a huge collection of test data in the repository where the configuration is maintained, but it doesn't contain one specific sketch intended to serve for this sort of purpose.

So I concatenated all the "targeted" test data files into the code below. That test data is designed to provide 100% coverage of the ClangFormat 14.0.0 configuration options (which the official Arduino sketch "samples" test data is not guaranteed to do).

Due to the nature of the content, and the concatenation, this is not a valid program in this form, but it is something ClangFormat can process.

If you put this code into a sketch and then run an "Auto Format" on it using the IDE build from this PR, you should see no diff when comparing that sketch to the file formatted by running clang-format on the file directly using the .clang-format configuration file from here.

The command for directly formatting would look something like this:

clang-format -i --style=file:.clang-format foo.cpp

You will see a diff if you compare the Auto Format output from a previous version of the IDE with the one from this PR. That is the result of the unavoidable or intentional configuration changes made in this PR (which are more thoroughly documented in the commit messages here).

class Foo {
public:
  protected:
    private:
};
void foo(int arg1, int arg2) {
  (void)arg1;
  (void)arg2;
}

void bar() {
  foo(42,
    1234);
  foo(42,
      1234);
}
struct Foo_t {
  int bar;
  int baz;
};

Foo_t pippo[] = {
  {1,   11},
  { 11, 1 },
};

Foo_t pluto[] = {
  { 1, 11},
  {11,  1},
};

Foo_t paperino[] = {
  { 1, 11 },
  { 11, 1 },
};
int a  = 42;
int bb = 42;

int ccc = 42;
int dddd = 42;
struct Foo_t {
  int a  : 1;
  int bb : 16;

  int ccc : 1;
  int dddd : 16;
};
int  a = 42;
long b = 42;

int c = 42;
long d = 42;
#define FOO_A  42
#define FOO_BB 42

#define FOO_CCC 42
#define FOO_DDDD 42
#define FOO \
	int a; \
	int bb; \
	int ccc; \
	int dddd; \
	int e;

#define BAR \
	int a;    \
	int bb;   \
	int ccc;  \
	int dddd; \
	int e;

#define BAZ                                                                                                            \
	int a;                                                                                                               \
	int bb;                                                                                                              \
	int ccc;                                                                                                             \
	int dddd;                                                                                                            \
	int e;
int foo = 42 +
  1234;

int bar = 42 +
          1234;

int baz = 42
          + 1234;

int qux = 42
        + 1234;

int a;      // foo
int b = 42; // foo

int c;  // foo
int d = 42; // foo
void foo(int arg1, int arg2) {
  (void)arg1;
  (void)arg2;
}

void bar() {
  foo(
    42, 1234);

  foo(42,
      1234);
}
class Foo {
  Foo();
  Foo(int);
  int bar;
  int baz;
};

Foo::Foo() :
  bar(42), baz(1234) {}

Foo::Foo(int qux) :
  bar(qux),
  baz(1234) {}
void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
  int foo, int bar, int baz);
void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
  int foo, int bar, int baz) {

  (void)foo;
  (void)bar;
  (void)baz;
}

void bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(int foo,
                                                                                                             int bar,
                                                                                                             int baz);
void bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(int foo,
                                                                                                             int bar,
                                                                                                             int baz) {

  (void)foo;
  (void)bar;
  (void)baz;
}
void foo() {
  while (true) {
  }

  while (true) {}

  while (true) {
    continue;
  }
}
void foo() {
  switch (1) {
    case 2: break;
    case 3:
      break;
  }
}
enum Foo_t { A, B };

enum Bar_t {
  C,
  D
};
void foo() {}

void bar() {
}

int baz() { return 42; }

int qux() {
  return 42;
}

class Pippo {
  void foo() {}

  void bar() {
  }

  int baz() { return 42; }

  int qux() {
    return 42;
  }
};
void foo() {
  bool a = true;

  if (a)
    return;
  if (a)
    return;
  else if (a)
    return;
  else
    return;
  if (a)
    return;
  else if (a) {
    return;
  } else {
    return;
  }

  if (a) return;
  if (a)
    return;
  else if (a)
    return;
  else
    return;
  if (a)
    return;
  else if (a) {
    return;
  } else {
    return;
  }

  if (a) return;
  if (a) return;
  else if (a)
    return;
  else
    return;
  if (a) return;
  else if (a) {
    return;
  } else {
    return;
  }

  if (a) return;
  if (a) return;
  else if (a) return;
  else return;
  if (a) return;
  else if (a) {
    return;
  } else {
    return;
  }
}
auto foo = []() {};

auto bar = []() {
};

auto baz = []() {
  return 42;
};

void qux(void (*)()) {}
void pippo() {
  qux([]() {});
}
void foo() {
  while (true) continue;

  while (true)
    continue;

  while (true) {
    continue;
  }
}
int foo();

int foo() { return 42; }

class Bar {
  int foo() { return 42; }
};

int
baz();

int
baz() {
  return 42;
}

class Qux {
  int
  baz() {
    return 42;
  }
};
void foo() {
  char bar[] =
    "asdf"
    "zxcv";

  char baz[] = "asdf"
               "zxcv";

  (void)bar;
  (void)baz;
}
template<typename T> T foo() {}
template<typename T>
T bar() {}

template<typename T> T baz(int a,
                           int b) {
  (void)a;
  (void)b;
}
template<typename T>
T qux(int a,
      int b) {
  (void)a;
  (void)b;
}
void foo(int arg1, int arg2, int arg3) {
  (void)arg1;
  (void)arg2;
  (void)arg3;
}

void bar() {
  int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42;

  foo(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);

  foo(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
}
void foo(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
         int cccccccccccccccccccccccccccccccccccccccccccccccccc) {

  (void)aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
  (void)bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
  (void)cccccccccccccccccccccccccccccccccccccccccccccccccc;
}

void bar(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
         int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
         int cccccccccccccccccccccccccccccccccccccccccccccccccc) {

  (void)aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
  (void)bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
  (void)cccccccccccccccccccccccccccccccccccccccccccccccccc;
}
struct Foo_t {
  int foo : 2;
  int bar:2;
  int baz :2;
  int qux: 2;
};
void foo() {
  switch (1) {
    case 2:
      {
        break;
      }
    case 3: {
        break;
      }
  }
}
class Foo
{
public:
};

class Bar {
public:
};
void foo() {
  if (true)
  {
    return;
  }

  if (true) {
    return;
  }

  if (true &&
      true)
  {
    return;
  }

  if (true &&
      true) {
    return;
  }
}
enum Foo_t
{
  A,
  B
};

enum Bar_t {
  C,
  D
};
extern "C"
{
  int foo();
}

extern "C" {
  int bar();
}
void foo()
{
  return;
}

void bar() {
  return;
}
namespace
{
  __attribute__ ((unused))int foo;
}

namespace {
  __attribute__ ((unused))int bar;
}
struct Foo_t
{
  int bar;
};

struct Baz_t {
  int qux;
};
union Foo_t
{
  int bar;
};

union Baz_t {
  int qux;
};
void foo() {}

void bar() {
  try {
    foo();
  }
  catch (int e) {
    (void)e;
  }

  try {
    foo();
  } catch (int e) {
    (void)e;
  }
}
void foo() {
  if (true) {
    return;
  }
  else {
    return;
  }

  if (true) {
    return;
  } else {
    return;
  }
}
void foo(void (*)()) {}

void bar() {
  foo([]()
  {
    return;
  });

  foo([]() {
    return;
  });
}
void foo() {
  do {
    continue;
  }
  while (true);

  do {
    continue;
  } while (true);
}
void foo()
  {}

void bar()
{}
void foo() {
}

void bar() {}

void baz()
{
}

void qux() {}
namespace {
}

namespace
{
}

namespace {}

namespace
{}
class Foo {
};

class Bar
{
};

class Baz {};

class Qux
{};
int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42;

int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

int ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc =
  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

int ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd =
  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

int eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee =
  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

int fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
  = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
extern "C"
{
  void foo();
}

void foo()
{
  switch (1)
  {
    case 2:
      {
        break;
      }
  }

  if (true)
  {
    return;
  }

  do {
    continue;
  } while (true);
}

void bar()
{
  try
  {
    foo();
  }
  catch (int e)
  {
    (void)e;
  }
  try
  {
    foo();
  }
  catch (int e)
  {
    (void)e;
  }
}

class Foo
{
public:
};

enum Foo_t
{
  A,
  B
};

namespace
{
const int foo = 42;
}

struct Bar_t
{
  int foo;
};

union Baz_t
{
  int foo;
};
extern "C" {
  void foo();
}

void foo() {
  switch (1) {
    case 2: {
        break;
      }
  }

  if (true) {
    return;
  }

  do {
    continue;
  } while (true);
}

void bar() {
  try {
    foo();
  } catch (int e) {
    (void)e;
  }
  try {
    foo();
  } catch (int e) {
    (void)e;
  }
}

class Foo {
public:
};

enum Foo_t {
  A,
  B
};

namespace {
const int foo = 42;
}

struct Bar_t {
  int foo;
};

union Baz_t {
  int foo;
};
extern "C"
  {
  void foo();
  }

void foo()
  {
  switch (1)
    {
      case 2:
        {
        break;
        }
    }

  if (true)
    {
    return;
    }

  do {
    continue;
    } while (true);
  }

void bar()
  {
  try
    {
    foo();
    }
  catch (int e)
    {
    (void)e;
    }
  try
    {
    foo();
    }
  catch (int e)
    {
    (void)e;
    }
  }

class Foo
  {
public:
  };

enum Foo_t
  {
  A,
  B
  };

namespace
  {
const int foo = 42;
  }

struct Bar_t
  {
  int foo;
  };

union Baz_t {
  int foo;
  };
template<typename T>
concept foo = requires(T bar) {
  (void)bar;
};

template<typename T> concept baz = requires(T bar) {
  (void)bar;
};
void foo() {
  bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = true;

  bool bar = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
               ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
               : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

  bar = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?
          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :
          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

  (void)bar;
}
class Foo {
  Foo();
  Foo(int);
  Foo(int, int);
  int bar;
  int baz;
};

Foo::Foo()
  : bar(42),
    baz(42) {}

Foo::Foo(int qux)
  : bar(qux)
  , baz(42) {}

Foo::Foo(int qux, int pippo) :
  bar(qux),
  baz(pippo) {}
class Foo {};
class Bar {};

class Baz
  : Foo,
    Bar {};

class Qux
  : Foo
  , Bar {};

class Pippo :
  Foo,
  Bar {};
char foo[] = "veryVeryVeryVery"
             "VeryVeryVeryVeryVeryVery"
             "VeryVeryVeryVeryVeryVeryVery"
             "VeryVeryVeryVeryVeryVeryVeryVery"
             "VeryVeryVeryVeryVeryVeryVery"
             "VeryVeryVeryVeryVeryVeryVeryVeryVeryLongString";

char bar[] = "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString";
// VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong
namespace foo { namespace bar {
}}

namespace baz {
namespace qux {
}
}
class Foo {
  Foo();
  Foo(int);
  int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
  int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
  int ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc;
};

Foo::Foo()
  : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(42), bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(42), ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc(42) {}

Foo::Foo(int bar)
  : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bar),
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(42),
    ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc(42) {}
class Foo {
  Foo();
  Foo(int);
  Foo(int, int);
  int pippo;
  int pluto;
  int paperino;
};
class Bar {};
class Baz {};

class Qux
: Foo,
  Bar,
    Baz {};

Foo::Foo()
: pippo(42),
  pluto(42),
    paperino(42) {}
int foo =
42;
int foo[] = {42, 1234};

int bar[] = { 42, 1234 };
// this file intentionally has CRLF line endings
int* foo;
int* bar;
int * baz;
int *qux;

void pippo(int& foo) {
  (void)foo;
}
void pluto(int & foo) {
  (void)foo;
}
void paperino(int &foo) {
  (void)foo;
}
class Foo {
public:
  int foo;
};

class Bar {
public:
  int foo;

private:

  int bar;
};

class Baz {
public:

  int foo;
};
class Foo {
public:
private:
  int foo;
protected:
};

class Bar {
public:

private:
  int foo;
protected:
};

class Baz {
public:
private:
  int foo;

protected:
};

class Qux {
public:

private:
  int foo;

protected:
};
namespace foo {
}

namespace bar {
}  // namespace baz
#include "include/b.h"
#include <bb.h>
#include "include/a.h"
#include <aa.h>

#include "include/d.h"
#include <dd.h>
#include "include/c.h"
#include <cc.h>
class Foo {
    int bar;

  public:
    int baz;
};

class Pippo {
  int pluto;

public:
  int paperino;
};
void foo() {
  switch (1) {
    case 2:
      {
        break;
      }
    case 3: {
      break;
    }
  }
}

void foo() {
  switch (1) {
    case 2:
      break;
  case 3:
    break;
  }
}
extern "C" {
  void foo();
void bar();
}
void foo() {
  bar:
baz:

  goto bar;
  goto baz;
}
#if defined(FOO)
#define BAR
#elif defined(BAZ)
#  define QUX
#else
  #define PIPPO
#endif
template<typename T>
  requires(true)
T foo() {}

template<typename T>
requires(true)
T bar() {}
void foo() {
int bar;
  (void)bar;
    int baz;
      (void)baz;
}
void
  foo() {}

void
bar() {}
int foo[] = {
  42,
  1234
};

int bar[] = {
  42,
  1234,
};
void foo() {
  if (true) {

    return;
  }

  if (true) {
    return;
  }
}
void foo(void (*)()) {}

void bar() {
  foo(
    []() {
      // baz
    });

  foo(
    []() {
    // baz
  });
}
int foo;






















int bar;
namespace {
const int foo = 42;
  const int bar = 42;
namespace baz {
const int qux = 42;
}
  namespace pippo {
    const int pluto = 42;
  }
}
#if defined(FOO)
#define BAR
#elif defined(BAZ)
  #define QUX
#else
    #define PIPPO
#endif
class Foo {
  Foo();
  Foo(int);
  Foo(int, int);
  Foo(int, int, int);
  Foo(int, int, int, int);
  int a;
  int b;
  int c;
  int dddddddddddddddddddddddddddddddddddddddddddddddddd;
  int eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
  int ffffffffffffffffffffffffffffffffffffffffffffffffff;
  int d;
  int e;
  int f;
  int ggggggggggggggggggggggggg;
  int hhhhhhhhhhhhhhhhhhhhhhhhh;
  int iiiiiiiiiiiiiiiiiiiiiiiii;
};

Foo::Foo()
  : a(42),
    b(1234),
    c(11) {}

Foo::Foo(int bar)
  : dddddddddddddddddddddddddddddddddddddddddddddddddd(bar), eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee(1234),
    ffffffffffffffffffffffffffffffffffffffffffffffffff(11) {}

Foo::Foo(int bar, int baz) : a(bar), b(baz), c(11) {}

Foo::Foo(int bar, int baz, int qux)
  : dddddddddddddddddddddddddddddddddddddddddddddddddd(bar),
    eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee(baz),
    ffffffffffffffffffffffffffffffffffffffffffffffffff(qux) {}

Foo::Foo(int bar, int baz, int qux, int pippo)
  : ggggggggggggggggggggggggg(bar), hhhhhhhhhhhhhhhhhhhhhhhhh(baz), iiiiiiiiiiiiiiiiiiiiiiiii(qux) {
  (void)pippo;
}
int* foo;
int *bar;
int * baz;

void pippo(int& foo) {
  (void)foo;
}
void pluto(int &foo) {
  (void)foo;
}
void paperino(int & foo) {
  (void)foo;
}
const int foo = 42;
int const bar = 42;
void pippo(int& foo) {
  (void)foo;
}
void pluto(int &foo) {
  (void)foo;
}
void paperino(int & foo) {
  (void)foo;
}
// foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo
// foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo
// foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo

/* bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar
 * bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar
 * bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar */

// foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo

/* bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar */
void foo() {
  if (true)
    return;

  if (true) {
    return;
  }
}
int foo;

void bar() {}
void baz() {}

void qux() {}

void pippo() {}

void pluto() {}
void paperino() {}
namespace {
}

namespace {
__attribute__((unused)) int foo;
}

namespace {
__attribute__((unused)) int bar;
__attribute__((unused)) int baz;
}

namespace {
__attribute__((unused)) int pippo;
__attribute__((unused)) int pluto;
__attribute__((unused)) int paperino;
}
#include "include/b.h"
#include "include/a.h"
#include <bb.h>
#include <aa.h>
namespace a {
int aa;
int ab;
}
namespace b {
int ba;
int bb;
}

using b::bb;
using b::ba;
using a::ab;
using a::aa;
int foo = (int) 42;

int bar = (int)42;
bool foo() {
  return ! true;
  return !true;
}
template <typename T> T foo() {}

template<typename T> T bar() {}
void* const* foo = nullptr;
void* const * bar = nullptr;
void foo() {
  int bar = 42;
  bar += 1;

  int baz= 42;
  baz+= 1;
}
void foo() {
  switch (1) {
    case 2 : break;
    case 3: break;
  }
}
int foo {};

int bar{};
class Foo {
  Foo();
  Foo(int);
  int bar;
};

Foo::Foo() : bar(42) {}

Foo::Foo(int baz): bar(baz) {}
class Foo {};

class Bar : Foo {};

class Baz: Foo {};
void foo() {
  if(true) {
    foo();
  }
}

void bar () {
  if (true) {
    foo ();
  }
}
void foo() {
  if (true) {}
  if(true) {}
}

void bar (int);
void baz(int);

void bar (int qux) {
  (void)qux;
}
void baz(int qux) {
  (void)qux;
}

#if (true)
#endif
#if(true)
#endif

class Foo {
public:
  Foo(){};
  Foo(int baz)
    : bar(baz) {}
  int bar;

  Foo operator++ (int qux) {
    (void)qux;
    return Foo(42);
  }

  Foo operator--(int qux) {
    (void)qux;
    return Foo(42);
  }
};

void pippo() {}
void pluto () {}
void foo() {
  for (char bar : "baz") {
    (void) bar;
  }

  for (char bar: "baz") {
    (void) bar;
  }
}
int foo [42];
int bar[42];
void foo() { }

void bar() {}
void foo( ) {
  foo( );
}

void bar() {
  bar();
}
//foo
// bar
//  baz
template<int foo> void bar() {}

void baz() {
  bar< 42 >();
  bar<42>();
}
int foo = ( int )42;

int bar = (int)42;
void foo() {
  if ( true ) {}
  if (true) {}
}
//foo
// bar
//  baz
void foo( int bar ) {
  (void)bar;
}

void baz(int qux) {
  foo( qux );

  foo(qux);
}
int foo[ 42 ];

int bar[42];
#include <set>
#include <vector>

std::vector<std::set<int> > foo;

std::vector<std::set<int>> bar;
// This test data must have multiple indentation levels in order to provide sufficient coverage of the unintuitive
// interaction between IndentWidth and TabWidth. See the TabWidth option notes for details.

void foo() {
  int bar =
    42;
  (void)bar;
  {
    int baz =
      42;
    (void)baz;
    {
      int qux =
        42;
      (void)qux;
    }
  }
}
// this file intentionally has CRLF line endings
// This test data must have multiple indentation levels in order to provide sufficient coverage of how UseTab is
// affected by the unintuitive interaction between IndentWidth and TabWidth. See the TabWidth option notes for details.

int a;                                   // foo
int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;  // foo
void bar() {
  int baz =
    42;
  (void)baz;
  {
    int qux =
      42;
    (void)qux;
    {
      int pippo =
        42;
      (void)pippo;
    }
  }
}

@per1234
Copy link
Contributor Author

per1234 commented Aug 4, 2022

One thing that came to my mind; checking the escaping when starting the IDE2 on Windows from CMD.exe, PowerShell, and GitBash.

I did a crude test of this by just checking for a diff of the formatted output of the sketch above when the was IDE started from each and there was no diff. However, it is possible that there could be differences in the interpretation of the clang-format command that are not causing a change to the formatter output (e.g., the problematic IncludeCategories key content is not used by the configuration from this PR due to SortIncludes being set to Never).

The better way to verify this would be to do a diff on the output produced by the IDE running the command:

clang-format --style=<style argument produced by IDE> --dump-config

I did a bit of fumbling around with the clang-formatter.ts code to try to get that output, but did not have any success so far.


The caret escaping used for Windows in this PR is cmd-specific. PowerShell uses ` instead:

https://docs.microsoft.com/en-ca/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.2

Copy link
Contributor

@kittaakos kittaakos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified it on Windows starting the IDE2 from CMD.EXE, Git Bash, and PowerShell, and on macOS. The instructions were great. Excellent work, Per 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: code Related to content of the project itself topic: infrastructure Related to project infrastructure type: enhancement Proposed improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Auto format configuration doesn't match classic Arduino IDE
2 participants