Re: [PATCH v2] .clang-format: introduce the use of clang-format

2015-01-21 Thread Jeff King
On Wed, Jan 21, 2015 at 12:01:27PM -0500, Ramkumar Ramachandra wrote:

 Instead of manually eyeballing style in reviews, just ask all
 contributors to run their patches through [git-]clang-format.

Thanks for mentioning this; I hadn't seen the tool before.

I didn't see it mentioned here, but for those who are also new to the
tool, it has modes both for checking the content itself as well as diffs
(so you are not stuck wading through its reformats of code you didn't
touch).

 +BreakBeforeBraces: Linux
 [...]
 +BreakBeforeBraces: Stroustrup

These seem conflicting. It looks like you added Stroustrup to keep the
brace on the line with the struct keyword. But this does the wrong
thing for cuddled elses like:

  if (...) {
 ...
  } else {
 ...
  }

I don't think clang-format has a mode that expresses our style.

I ran some of my recent patches through clang-format-diff, and it
generated quite a bit of output. Here are a few notes on what I saw.
Feel free to ignore. They are not your problem, but others evaluating
the tool might find it useful (and a few of them might suggest some
settings for .clang-format).

 - It really wants to break function declarations that go over the
   column limit, even though we often do not do so. I think we're pretty
   inconsistent here, and I'd be fine going either way with it.

 - It really wanted to left-align some of my asterisks, like:

 struct foo_list {
   ...
 } * foo, **foo_tail;

   The odd thing is that it gets the second one right, but not the first
   one (which should be *foo with no space). Setting:

 DerivePointerAlignment: false
 PointerAlignment: Right

   cleared it up, but I'm curious why the auto-deriver didn't work.

 - It really doesn't like list-alignment, like:

  #define FOO1
  #define LONGER 2

   and would prefer only a single space between FOO and 1. I think
   I'm OK with that, but we have a lot of aligned bits in the existing
   code.

 - It really wants to put function __attribute__ macros on the same line
   as the function. We often have it on a line above (especially it can
   be so long). I couldn't find a way to specify this.

 - I had a long ternary operator broken across three lines, like:

 foo = bar ?
   some_long_thing(...) :
   some_other_long_thing(...);

   It put it all on one long line, which was much less readable. I set
   BreakBeforeTernaryOperators to true, but it did nothing. I set it
   to false, and then it broke. Which seems like a bug. It also
   insisted on indenting it like:

 foo = bar ?
   some_long_thing(...) :
   some_other_long_thing(...);

which I found less readable.

So overall I think it has some promise, but I do not think it is quite
flexible enough yet for us to use day-to-day. I'm slightly dubious that
any automated formatter can ever be _perfect_ (sometimes
human-subjective readability trumps a hard-and-fast rule), but this
seems like it might have some promise. And over other indenters I have
seen:

  1. It's built on clang, so we know the parsing is solid.

  2. It can operate on patches (and generates patches for you to apply!
 You could add a git-add--interactive mode to selectively take its
 suggestions).

Again, thanks for sharing.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] .clang-format: introduce the use of clang-format

2015-01-21 Thread Ramkumar Ramachandra
Jeff King wrote:
 On Wed, Jan 21, 2015 at 12:01:27PM -0500, Ramkumar Ramachandra wrote:
 +BreakBeforeBraces: Linux
 [...]
 +BreakBeforeBraces: Stroustrup

Oh, oops.

  - It really wants to break function declarations that go over the
column limit, even though we often do not do so. I think we're pretty
inconsistent here, and I'd be fine going either way with it.

  - It really wanted to left-align some of my asterisks, like:

  struct foo_list {
...
  } * foo, **foo_tail;

The odd thing is that it gets the second one right, but not the first
one (which should be *foo with no space). Setting:

  DerivePointerAlignment: false
  PointerAlignment: Right

cleared it up, but I'm curious why the auto-deriver didn't work.

Sounds like a bug.

  - It really doesn't like list-alignment, like:

   #define FOO1
   #define LONGER 2

and would prefer only a single space between FOO and 1. I think
I'm OK with that, but we have a lot of aligned bits in the existing
code.

  - It really wants to put function __attribute__ macros on the same line
as the function. We often have it on a line above (especially it can
be so long). I couldn't find a way to specify this.

You have to compromise a bit if you want to use an auto-formatting
tool, without losing your head patching every little detail :)

  - I had a long ternary operator broken across three lines, like:

  foo = bar ?
some_long_thing(...) :
some_other_long_thing(...);

It put it all on one long line, which was much less readable. I set
BreakBeforeTernaryOperators to true, but it did nothing. I set it
to false, and then it broke. Which seems like a bug. It also
insisted on indenting it like:

  foo = bar ?
some_long_thing(...) :
some_other_long_thing(...);

 which I found less readable.

To be honest, the LLVM community doesn't fix bugs just because they
can be fixed: it's quite heavily driven by commercial interest. And I
really don't find long ternary operators in a modern C++ codebase.

 I'm slightly dubious that
 any automated formatter can ever be _perfect_ (sometimes
 human-subjective readability trumps a hard-and-fast rule), but this
 seems like it might have some promise.

It works almost perfectly for the LLVM umbrella of projects. When they
want to change a coding convention (like leading Uppercase for
variable names), they write a clang-tidy thing to do it automatically.

 So overall I think it has some promise, but I do not think it is quite
 flexible enough yet for us to use day-to-day.

The big negative is that it will probably never be. I'll try to look
at the larger issues later this week, if you can compromise on the
fine details that are probably too hard to fix.

   2. It can operate on patches (and generates patches for you to apply!
  You could add a git-add--interactive mode to selectively take its
  suggestions).

There's a git-clang-format in the $CLANG_ROOT/tools/clang-format/. I do:

   $ g cf @~

... with the appropriate aliases.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] .clang-format: introduce the use of clang-format

2015-01-21 Thread Jeff King
On Wed, Jan 21, 2015 at 04:28:00PM -0500, Ramkumar Ramachandra wrote:

  So overall I think it has some promise, but I do not think it is quite
  flexible enough yet for us to use day-to-day.
 
 The big negative is that it will probably never be. I'll try to look
 at the larger issues later this week, if you can compromise on the
 fine details that are probably too hard to fix.

The key to me is that we do not have necessarily take every suggestion
the tool makes. So it does not have to be perfect, just pretty good.

But...I think it is not quite so simple. The clang-format-diff script
(and git-clang-format) _do_ seem to operate on more than just the lines
I've changed. I'm not clear on whether they're examining the whole file
(just with the patches applied), or there's something in between
happening.

So rejecting the tool's suggestion one day may mean it suggests the same
change to you any other time you touch nearby parts of the file, which
could be annoying.

2. It can operate on patches (and generates patches for you to apply!
   You could add a git-add--interactive mode to selectively take its
   suggestions).
 
 There's a git-clang-format in the $CLANG_ROOT/tools/clang-format/. I do:
 
$ g cf @~
 
 ... with the appropriate aliases.

Neat. Debian's package does not ship with that. I hacked-in very
rudimentary interactive-add support for clang-format-diff (below) before
getting your response. It would be better built around git-clang-format
--diff (though that script would need to be taught to do the right
thing with the --color argument).

However, because of the suggest the same change thing I mentioned
above, I am not sure whether interactively selecting is a good idea or
not.  You might end up having to say no to the same suggestions a lot.

Anyway, here it is, for reference. You can use it like:

  git add--interactive --patch=format --

and you could probably even stick an exec line into an interactive
rebase to go through and fixup individual patches in a whole series.

---
diff --git a/.gitignore b/.gitignore
index a052419..6f5b815 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@
 /git-checkout-index
 /git-cherry
 /git-cherry-pick
+/git-clang-format-diff
 /git-clean
 /git-clone
 /git-column
diff --git a/Makefile b/Makefile
index c44eb3a..113534e 100644
--- a/Makefile
+++ b/Makefile
@@ -455,6 +455,7 @@ unexport CDPATH
 
 SCRIPT_SH += git-am.sh
 SCRIPT_SH += git-bisect.sh
+SCRIPT_SH += git-clang-format-diff.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index c725674..fd83adf 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -167,6 +167,16 @@ my %patch_modes = (
FILTER = undef,
IS_REVERSE = 0,
},
+   'format' = {
+   DIFF = 'clang-format-diff',
+   APPLY = sub { apply_patch_for_checkout_commit '', @_ },
+   APPLY_CHECK = 'apply',
+   VERB = 'Apply',
+   TARGET = 'to index and worktree',
+   PARTICIPLE = 'applying',
+   FILTER = undef,
+   IS_REVERSE = 0
+   },
 );
 
 my %patch_mode_flavour = %{$patch_modes{stage}};
@@ -1591,6 +1601,15 @@ sub process_args {
   'checkout_head' : 
'checkout_nothead');
$arg = shift @ARGV or die missing --;
}
+   } elsif ($1 eq 'format') {
+   $patch_mode = $1;
+   $arg = shift @ARGV or die missing --;
+   if ($arg eq '--') {
+   $patch_mode_revision = 'HEAD^';
+   } else {
+   $patch_mode_revision = $arg;
+   $arg = shift @ARGV or die missing --;
+   }
} elsif ($1 eq 'stage' or $1 eq 'stash') {
$patch_mode = $1;
$arg = shift @ARGV or die missing --;
diff --git a/git-clang-format-diff.sh b/git-clang-format-diff.sh
new file mode 100755
index 000..9351883
--- /dev/null
+++ b/git-clang-format-diff.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# This is what it's called in the Debian package, but it seems
+# like there ought to be a symlink without the version...
+CFD=clang-format-diff-3.6
+
+# Strip out --color, as clang's patch reader cannot handle it.
+# Robustly handling arrays in bourne shell is insane.
+eval set -- $(
+   for i in $@; do
+   test --color = $i  continue
+   printf  '
+   printf '%s' $i | sed s/'/'''/g
+   printf '
+   done
+)
+
+git diff-index -p $@ |
+$CFD -p1 |
+sed -e 's,^--- ,a/,' -e 's,^+++ ,b/,'
--
To