Repository: coala/coala

Issue:
affected_code place holder of --format option should produce more verbose results
When run coala with `--format "affected_code: {affected_code}", it produces results with unnecessary information.

### Steps to reproduce
Create a file with with some affected lines in it. In this case we will use `something.py` as our file name and trailing white spaces to make our code affected.
Now run `coala -I --bears SpaceConsistencyBear --files something.py -S use_spaces=True --format "affected_code: {affected_code}"`

### Actual Results
The following line is printed

    affected_code: (<SourceRange object(start=<SourcePosition object(file='/home/abhisek/Github/coala/something.py', line=4, column=None) at 0x7fef45c76780>, end=<SourcePosition object(file='/home/abhisek/Github/coala/something.py', line=4, column=None) at 0x7fef45c76c88>) at 0x7fef45c76d30>,)

### Expected Results
Maybe something like the following

    affected_code: <<file_name>>:
                               FROM: line_number: column_number
                               TO:   line_number: column_number
In this case

    affected_code: /home/abhisek/Github/coala/something.py:
                               FROM: 4: None
                               TO:   4: None


Discussion:
I would use a format that does not contain `\n`s (simplifies often parsing with regexes), but generally I like the idea :+1:
But I have not used any `\n` in my format. The source code contains `\n`s.
don't understand you :O
I mean your expected format should look like
```
affected_code: /home/abhisek/Github/coala/something.py: FROM 4: None TO: 4: None
```
instead of
```
affected_code: /home/abhisek/Github/coala/something.py:
                           FROM: 4: None
                           TO:   4: None
```
Oh I misunderstood you. I thought you are talking about the format `--format "affected: {affected}"`, hence I thought I've not used any `\n`.

The expected result *may* look something like the following.

    affected_code: /home/abhisek/Github/coala/something.py:
                   From: 4: None
                   To:   4: None

but It doesn't necessarily have to be that way. The idea is to make the information more verbose. I thought it will be useful for the user if we print the line and column information in a separate line. If we print on a separate line it is easy to see, where exactly the problem is and it is more clean. And yes, as you said it will add some extra work for us, but at the end it'll be more useful.
`--format` is primarily for printing results in a simple parsable format. For humans you can use our default cli without `--format` :)
Oh.. that is also right :). I over thought about that. thanks
I'd like to work on this issue. Would you mind assigning it to me?
@vijeth-aradhya before you start, how do you think the format for `affected_code` should look like?
@Makman2 I'm assuming `{affected_code}` will be listed as one of the placeholders, as it is not a part of it yet.
And, about the format for it -
`affected_code: /home/abhisek/Github/coala/something.py: FROM 4: None TO: 4: None` 
I think this would be a good enough representation :+1: 

okay cool, some ideas:
```
FROM 4: None TO: 4:NONE
```
I would remove the spaces after the colon:
```
FROM 4:None TO 4:NONE
```
(and also the colon after `TO` :D)

Also when we have `NONE` for columns, this means the complete line is meant, not sure if you want to compress the format then to
```
FROM 4 TO 4
```
@Makman2 I think the way to go about this is _not_ to give all the attributes of the Result Class, since some of the variables there are **NOT** in the list of placeholders like `{diffs}`, `{confidence}` ( they still work if I give them in `--format` )
If you think all of them are required, and we have to just add `{affected_code}`, then we have to remove the existing tuple representation of `affected_code` somehow, and add a string like the one you suggested above
sorry can't follow you what you mean exactly, especially with

>  I think the way to go about this is not to give all the attributes of the Result Class

:/

Resolving patch:
diff --git a/coalib/output/ConsoleInteraction.py b/coalib/output/ConsoleInteraction.py
--- a/coalib/output/ConsoleInteraction.py
+++ b/coalib/output/ConsoleInteraction.py
@@ -304,25 +304,28 @@ def print_results_formatted(log_printer,
 
     for result in result_list:
         severity_str = RESULT_SEVERITY.__str__(result.severity)
+        format_args = vars(result)
         try:
             if len(result.affected_code) == 0:
+                format_args['affected_code'] = None
                 print(format_str.format(file=None,
                                         line=None,
                                         end_line=None,
                                         column=None,
                                         end_column=None,
                                         severity_str=severity_str,
-                                        **result.__dict__))
+                                        **format_args))
                 continue
 
             for range in result.affected_code:
+                format_args['affected_code'] = range
                 print(format_str.format(file=range.start.file,
                                         line=range.start.line,
                                         end_line=range.end.line,
                                         column=range.start.column,
                                         end_column=range.end.column,
                                         severity_str=severity_str,
-                                        **result.__dict__))
+                                        **format_args))
         except KeyError as exception:
             log_printer.log_exception(
                 'Unable to print the result with the given format string.',
diff --git a/coalib/parsing/DefaultArgParser.py b/coalib/parsing/DefaultArgParser.py
--- a/coalib/parsing/DefaultArgParser.py
+++ b/coalib/parsing/DefaultArgParser.py
@@ -100,7 +100,7 @@ def default_arg_parser(formatter_class=None):
         help='output results with a custom format string, e.g. '
              '"Message: {message}"; possible placeholders: '
              'id, origin, file, line, end_line, column, end_column, '
-             'severity, severity_str, message')
+             'severity, severity_str, message, affected_code')
 
     config_group = arg_parser.add_argument_group('Configuration')
 
diff --git a/coalib/results/SourceRange.py b/coalib/results/SourceRange.py
--- a/coalib/results/SourceRange.py
+++ b/coalib/results/SourceRange.py
@@ -126,6 +126,38 @@ def __json__(self, use_relpath=False):
             _dict['file'] = relpath(_dict['file'])
         return _dict
 
+    def __str__(self):
+        """
+        Creates a string representation of the SourceRange object.
+
+        If the whole file is affected, then just the filename is shown.
+
+        >>> str(SourceRange.from_values('test_file', None, None, None, None))
+        '...test_file'
+
+        If the whole line is affected, then just the filename with starting
+        line number and ending line number is shown.
+
+        >>> str(SourceRange.from_values('test_file', 1, None, 2, None))
+        '...test_file: L1 : L2'
+
+        This is the general case where particular column and line are
+        specified. It shows the starting line and column and ending line
+        and column, with filename in the beginning.
+
+        >>> str(SourceRange.from_values('test_file', 1, 1, 2, 1))
+        '...test_file: L1 C1 : L2 C1'
+        """
+        if self.start.line is None and self.end.line is None:
+            format_str = '{0.start.file}'
+        elif self.start.column is None and self.end.column is None:
+            format_str = '{0.start.file}: L{0.start.line} : L{0.end.line}'
+        else:
+            format_str = ('{0.start.file}: L{0.start.line} C{0.start.column}' +
+                          ' : L{0.end.line} C{0.end.column}')
+
+        return format_str.format(self)
+
     def __contains__(self, item):
         return (super().__contains__(item) and
                 self.start.file == item.start.file)


Test patch: