1# -*- coding: utf-8 -*-
2# Copyright (C) 2016 Adrien Vergé
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17import string
18
19import yaml
20
21from yamllint.linter import LintProblem
22
23
24def spaces_after(token, prev, next, min=-1, max=-1,
25                 min_desc=None, max_desc=None):
26    if next is not None and token.end_mark.line == next.start_mark.line:
27        spaces = next.start_mark.pointer - token.end_mark.pointer
28        if max != - 1 and spaces > max:
29            return LintProblem(token.start_mark.line + 1,
30                               next.start_mark.column, max_desc)
31        elif min != - 1 and spaces < min:
32            return LintProblem(token.start_mark.line + 1,
33                               next.start_mark.column + 1, min_desc)
34
35
36def spaces_before(token, prev, next, min=-1, max=-1,
37                  min_desc=None, max_desc=None):
38    if (prev is not None and prev.end_mark.line == token.start_mark.line and
39            # Discard tokens (only scalars?) that end at the start of next line
40            (prev.end_mark.pointer == 0 or
41             prev.end_mark.buffer[prev.end_mark.pointer - 1] != '\n')):
42        spaces = token.start_mark.pointer - prev.end_mark.pointer
43        if max != - 1 and spaces > max:
44            return LintProblem(token.start_mark.line + 1,
45                               token.start_mark.column, max_desc)
46        elif min != - 1 and spaces < min:
47            return LintProblem(token.start_mark.line + 1,
48                               token.start_mark.column + 1, min_desc)
49
50
51def get_line_indent(token):
52    """Finds the indent of the line the token starts in."""
53    start = token.start_mark.buffer.rfind('\n', 0,
54                                          token.start_mark.pointer) + 1
55    content = start
56    while token.start_mark.buffer[content] == ' ':
57        content += 1
58    return content - start
59
60
61def get_real_end_line(token):
62    """Finds the line on which the token really ends.
63
64    With pyyaml, scalar tokens often end on a next line.
65    """
66    end_line = token.end_mark.line + 1
67
68    if not isinstance(token, yaml.ScalarToken):
69        return end_line
70
71    pos = token.end_mark.pointer - 1
72    while (pos >= token.start_mark.pointer - 1 and
73           token.end_mark.buffer[pos] in string.whitespace):
74        if token.end_mark.buffer[pos] == '\n':
75            end_line -= 1
76        pos -= 1
77    return end_line
78
79
80def is_explicit_key(token):
81    # explicit key:
82    #   ? key
83    #   : v
84    # or
85    #   ?
86    #     key
87    #   : v
88    return (token.start_mark.pointer < token.end_mark.pointer and
89            token.start_mark.buffer[token.start_mark.pointer] == '?')
90