gitar

Fix table display issues

Author
Maarten Vangeneugden
Date
Oct. 25, 2023, 5:30 p.m.
Hash
b8c45e62a81527ebd6fc1c6750ed2886be59462d
Parent
00cc338301ca90456910abe04fdea8b7ca3f4aff
Modified files
GitActions/CommitInfo.py
templates/gitar/commit.djhtml
templates/gitar/directory.djhtml

GitActions/CommitInfo.py

5 additions and 8 deletions.

View changes Hide changes
1
1
# formatted file in a commit. 
2
2
3
3
# The function returns a list 
4
4
5
5
# If one line is removed, and one line is added, and both have the same line
6
6
# number, then that should be regarded as a changed line, not a removed+added line.
7
7
# This holds for each non-broken list of removed+added lines.
8
8
9
9
from pydriller.domain.commit import ModificationType
10
10
from ..syntax import *
11
11
12
12
""" It's a lot of annoying glue code to transform a modified file object into
13
13
what we actually want: The data that needs to be passed to the Django template.
14
14
This convenience function accepts the modified file object as given by
15
15
Pydriller's Commit class, and returns a list of dicts, each dict representing
16
16
the information needed to properly present a file diff in the template.
17
17
"""
18
18
def prepare_and_process(modified_file):
19
19
    #print(modified_file.source_code)
20
20
    result = dict()
21
21
    result["object"] = modified_file  # Could come in handy
22
22
    result["change_type"] = modified_file.change_type
23
23
    result["html_code_after"] = code_to_HTML(
24
24
        modified_file.source_code,
25
25
        modified_file.filename)
26
26
    result["html_code_before"] = code_to_HTML(
27
27
        modified_file.source_code_before,
28
28
        modified_file.filename)
29
29
30
30
    if modified_file.change_type == ModificationType.ADD:
31
31
        result["path"] = modified_file.new_path
32
32
    elif modified_file.change_type == ModificationType.DELETE:
33
33
        result["path"] = modified_file.old_path
34
34
    elif modified_file.change_type == ModificationType.RENAME:
35
35
        result["path"] = modified_file.old_path +" → "+ modified_file.new_path
36
36
    elif modified_file.change_type == ModificationType.MODIFY:
37
37
        result["path"] = modified_file.old_path
38
38
39
39
    added = dict()
40
40
    deleted = dict()
41
41
    for number, line in modified_file.diff_parsed["added"]:
42
42
        added[number] = line
43
43
    for number, line in modified_file.diff_parsed["deleted"]:
44
44
        if result["path"] == "Challenge 4/Controller.java":
45
45
            #print("PING")
46
46
            pass
47
47
        deleted[number] = line
48
48
    if result["path"] == "Challenge 4/Controller.java":
49
49
        pass
50
50
        #print("NU CONTROLLER.jAVA")
51
51
        #print(modified_file.diff_parsed)
52
52
        #print(deleted)
53
53
    result["rows"] = process_file(
54
54
        result["html_code_before"],
55
55
        result["html_code_after"],
56
56
        added,
57
57
        deleted)
58
58
59
59
    # These three lists are going to be empty if the methods couldn't be detected
60
60
    deleted, transferred, new = process_methods(modified_file)
61
61
    if len(deleted) == len(transferred) == len(new) == 0:
62
62
        result["methods_available"] = False
63
63
    else:
64
64
        result["methods_available"] = True
65
65
        result["deleted_methods"] = deleted
66
66
        result["transferred_methods"] = transferred
67
67
        result["new_methods"] = new
68
68
    return result 
69
69
70
70
""" Sometimes, the methods in a file can be detected, which adds some nice
71
71
information """
72
72
def process_methods(modified_file):
73
73
    before_methods = modified_file.methods_before
74
74
    after_methods = modified_file.methods
75
75
    deleted_methods = []
76
76
    transferred_methods = []
77
77
    new_methods = []
78
78
79
79
    # Finding all transferred and deleted methods
80
80
    for before_method in before_methods:
81
81
        transferred = False
82
82
        for after_method in after_methods:
83
83
            if before_method.name == after_method.name:  # Match found
84
84
                transferred_methods.append((before_method, after_method))
85
85
                transferred = True
86
86
                break
87
87
        if not transferred:
88
88
            deleted_methods.append(before_method)
89
89
    # Finding all new methods
90
90
    for after_method in after_methods:
91
91
        transferred = False
92
92
        for _, am in transferred_methods:
93
93
            if after_method == am:
94
94
                transferred = True
95
95
                break
96
96
        if not transferred:
97
97
            new_methods.append(after_method)
98
98
99
99
    return deleted_methods, transferred_methods, new_methods
100
100
    
101
101
102
102
def process_file(source_before, source_after, additions, deletions): 
103
103
    rows = []
104
104
    # Counting from 1, because source code lines are counted from there
105
105
    # NOTE: Deletions komen wel degelijk goed binnen
106
106
    #print("deletions:")
107
107
    #print(deletions)
108
108
    before_count = 1
109
109
    after_count = 1
110
110
    while True:
111
111
        row = dict()
112
112
        #print("PROCESS_FILE")
113
113
        #print(deletions)
114
114
        #print(additions)
115
115
        # We check the deletion lines first; if a line was "changed", the
116
116
        # 'deleted' line needs to be listed first, and after that, the 'added'
117
117
        # line
118
118
        #print(str(before_count) + " -- " + str(after_count))
119
119
        if before_count in deletions:
120
120
            row["type"] = "deletion"
121
121
            row["old_num"] = before_count
122
122
            # Why source_before[] and not deletions[]?
123
123
            # Because source_before[] has been processed by Pygments, and thus
124
124
            # has the syntax highlighting in it. deletions[] is just plain text.
125
125
126
126
127
127
            # Look, I'm tired at the time of writing, and this line seems to be
128
128
            # kind of a dick so I'm just gonna try catch it and leave it like
129
129
            # that for now
130
130
            #try: 
131
131
                #row["line"] = source_before[before_count]
132
132
            print(len(source_before))
133
-
            print(before_count)
134
-
            if before_count == len(source_before):
+
133
            #print(before_count)
+
134
            if before_count == len(source_before):
135
135
                row["line"] = source_before[-1]
136
136
            else:
137
137
                row["line"] = source_before[before_count]
138
138
            #except:
139
139
                #pass
140
140
141
141
            before_count += 1
142
142
        elif after_count in additions:
143
143
            row["type"] = "addition"
144
144
            row["new_num"] = after_count
145
145
            # Idem for additions[]
146
146
            # Look, I'm tired at the time of writing, and this line seems to be
147
-
            # kind of a dick so I'm just gonna try catch it and leave it like
148
-
            # that for now
149
-
            try: 
150
-
                row["line"] = source_after[after_count]
+
147
                row["line"] = source_after[-1]
+
148
            else:
+
149
                row["line"] = source_after[after_count]
151
150
            except:
152
-
                pass
153
-
            after_count += 1
154
151
        else:  # No change to this particular line
155
152
            row["old_num"] = before_count
156
153
            row["new_num"] = after_count
157
154
            if len(source_before) > before_count:
158
155
                row["line"] = source_before[before_count] 
159
156
            elif len(source_after) > after_count:
160
157
                row["line"] = source_after[after_count] 
161
158
            else:  # No lines left
162
159
                break
163
160
            # If not end of both files, increment both counters anyway
164
161
            before_count += 1
165
162
            after_count += 1
166
163
        # Adding the new row to the list of rows
167
164
        rows.append(row)
168
165
    return rows
169
166
170
167
171
168
172
169
173
170
174
171
        
175
172
176
173
    
177
174

templates/gitar/commit.djhtml

5 additions and 0 deletions.

View changes Hide changes
1
1
{% load i18n %}
2
2
{% load humanize %}
3
3
{% load static %}
4
4
5
5
{% block title %}{{ repository_name }} | Gitar{% endblock title %}
6
6
7
7
{% block stylesheets %}
8
8
    {{ block.super }}
9
9
    <link rel="stylesheet" type="text/css" href="/static/website/syntax.css" />
10
10
    <link rel="stylesheet" type="text/css" href="/static/gitar/css/file.css" />
11
11
    <style>
12
12
    table.highlight {
13
13
        border-collapse: collapse;
14
14
    }
15
15
    table.highlight tr {
16
16
        line-height: 1em;
17
17
    }
18
18
19
19
    tr.deletion {
20
20
        background-color: rgba(255, 0, 0, .1);
21
21
    }
22
22
    tr.addition {
23
23
        background-color: rgba(0, 255, 0, .1);
24
24
    }
25
25
+
26
        /* Okay this makes the button stretch but whatever, it's better
+
27
           than trying to fight the tables */
+
28
        display: block;
+
29
    }
+
30
26
31
    section {
27
32
        overflow-x: scroll;
28
33
    }
29
34
        
30
35
    .symbol {
31
36
        text-align: right;
32
37
        /*font-weight: bolder;*/
33
38
    /* These vendor prefixes are still necessary, yeah...*/
34
39
    }
35
40
    .line-number {
36
41
        text-align: right;
37
42
        width: 3em;
38
43
        -moz-user-select: none;
39
44
        -webkit-user-select: none;
40
45
        -ms-user-select: none;
41
46
      user-select: none;
42
47
    }
43
48
    .line-number a {
44
49
        color: grey;
45
50
    }
46
51
47
52
    details span.opened {
48
53
        display: none;
49
54
    }
50
55
    details[open] span.opened {
51
56
         display: inline;
52
57
    }
53
58
    details[open] span.closed {
54
59
         display: none;
55
60
    }
56
61
    </style>
57
62
{% endblock stylesheets %}
58
63
59
64
{% block description %}
60
65
{{ repository_name }} {{ commit.hash|truncatechars:10 }}: {{ commit.msg }}
61
66
{% endblock description %}
62
67
63
68
{% block header %}
64
69
<header>
65
70
    <label for="nav-drawer-toggle"></label>
66
71
    <h1>{{ repository_name }}</h1>  
67
72
</header>
68
73
{% endblock header %}
69
74
70
75
{% block nav %}
71
76
<input id="nav-drawer-toggle" type="checkbox" />
72
77
<nav>
73
78
    <label for="nav-drawer-toggle">🡠</label>
74
79
    <h2>{{ repository_name }}</h2>
75
80
    <a class="nav-link" href="{% url 'gitar-index' %}">Gitar | Index</a>
76
81
    <a class="nav-link" href="{% url 'gitar-repository' repository_name %}">{{ repository_name }} | Index</a>
77
82
    <a class="nav-link" href="{% url 'about-index' %}">{% translate "Front page" %}</a>
78
83
    <hr class="half">
79
84
    {% for mod_file in modified_files %}
80
85
        <a class="nav-link" href="#{{ mod_file.path }}">{{ mod_file.path }}</a>
81
86
    {% endfor %}
82
87
</nav>
83
88
{% endblock nav %}
84
89
85
90
{% block main %}
86
91
87
92
<section class="emphasis">
88
93
    <h2>{{ first_line }}</h2>
89
94
    <p>{{ other_lines|safe }}</p>
90
95
    <dl>
91
96
        <dt>{% translate "Author" %}</dt>
92
97
        <dd>{{ commit.author.name }}</dd>
93
98
94
99
        <dt>{% translate "Date" %}</dt>
95
100
        <dd>{{ commit.committer_date|date:"DATETIME_FORMAT" }}</dd>
96
101
97
102
        <dt>{% translate "Hash" %}</dt>
98
103
        <dd><samp>{{ commit.hash }}</samp></dd>
99
104
100
105
        {% if commit.parents|length_is:"1" %}
101
106
        <dt>{% translate "Parent" %}</dt>
102
107
        {% else %}
103
108
        <dt>{% translate "Parents" %}</dt>
104
109
        {% endif %}
105
110
        {% for parent in commit.parents %}
106
111
        <dd><samp><a href="{% url "gitar-commit" repository_name parent %}">
107
112
        {{ parent }}
108
113
        </a></samp</dd>
109
114
        {% endfor %}
110
115
111
116
        {% if modified_files|length_is:"1" %}
112
117
        <dt>{% translate "Modified file" %}</dt>
113
118
        {% else %}
114
119
        <dt>{% translate "Modified files" %}</dt>
115
120
        {% endif %}
116
121
        {% for mod_file in modified_files %}
117
122
        <dd><a href="#{{ mod_file.path }}">{{ mod_file.path }}</a></dd>
118
123
        {% endfor %}
119
124
        {#<dt>{% translate "Child" %}</dt>#}
120
125
        {# <dd>{{ commit.author_date|date:"DATETIME_FORMAT" }}</dd>#}
121
126
        {# Gonna leave the email out for now, don't like email scrapers #}
122
127
        {# <dt>{% translate "E-mail" %}</dt> #}
123
128
        {# <dl>{{ commit.author.email }}</dl> #}
124
129
    </dl>
125
130
</section>
126
131
127
132
{% for mod_file in modified_files %}
128
133
<section>
129
134
    <h3 id="{{ mod_file.path }}">{{ mod_file.path }} <a href="#{{ mod_file.path }}"></a></h3>
130
135
        <p>
131
136
            {{ mod_file.object.added_lines }}
132
137
            {% blocktranslate count counter=mod_file.object.added_lines %}
133
138
            addition
134
139
            {% plural %}
135
140
            additions
136
141
            {% endblocktranslate %}
137
142
            {% translate "and" %}
138
143
            {{ mod_file.object.deleted_lines }}
139
144
            {% blocktranslate count counter=mod_file.object.deleted_lines %}
140
145
            deletion.
141
146
            {% plural %}
142
147
            deletions.
143
148
            {% endblocktranslate %}
144
149
        </p>
145
150
        {% if mod_file.methods_available %}
146
151
147
152
        {% endif %}
148
153
    <details open>
149
154
        <summary class="ripple"><span class="closed"> {% translate "View changes" %}</span><span class="opened"> {% translate "Hide changes" %}</span>
150
155
        </summary>
151
156
152
157
        <table class="highlight" style="font-family: 'Fira Code', monospace;">
153
158
        {% for row in mod_file.rows %}
154
159
        {% if row.type == "deletion" %}
155
160
        <tr class="deletion">
156
161
            <td id="{{ mod_file.path }}-A{{ row.old_num }}" class="line-number">
157
162
                <a href="#{{ mod_file.path }}-A{{ row.old_num }}" class="accent-on-hover-only"><pre>{{ row.old_num }}</pre>
158
163
            </a></td>
159
164
            <td class="line-number symbol">-</td>
160
165
        {% elif row.type == "addition" %}
161
166
        <tr class="addition">
162
167
            <td class="line-number symbol">+</td>
163
168
            <td id="{{ mod_file.path }}-B{{ row.new_num }}" class="line-number">
164
169
                <a href="#{{ mod_file.path }}-B{{ row.new_num }}" class="accent-on-hover-only"><pre>{{ row.new_num }}</pre>
165
170
            </a></td>
166
171
        {% else %}
167
172
        <tr class="nochange">
168
173
            <td id="{{ mod_file.path }}-A{{ row.old_num }}" class="line-number">
169
174
                <a href="#{{ mod_file.path }}-A{{ row.old_num }}" class="accent-on-hover-only"><pre>{{ row.old_num }}</pre>
170
175
            <td id="{{ mod_file.path }}-B{{ row.new_num }}" class="line-number">
171
176
                <a href="#{{ mod_file.path }}-B{{ row.new_num }}" class="accent-on-hover-only"><pre>{{ row.new_num }}</pre>
172
177
            </a></td>
173
178
        {% endif %}
174
179
            <td style="padding-left: 1em;"><pre>{{ row.line|safe }}</pre></td>
175
180
        </tr>
176
181
        {% endfor %}
177
182
        </table>
178
183
    </details>
179
184
</section>
180
185
{% endfor %}
181
186
182
187
{% endblock main %}
183
188

templates/gitar/directory.djhtml

3 additions and 0 deletions.

View changes Hide changes
1
1
{% load i18n %}
2
2
{% load humanize %}
3
3
{% load static %}
4
4
5
5
{% block title %}{{ repository_name }} | Gitar{% endblock title %}
6
6
7
7
{% block stylesheets %}
8
8
    {{ block.super }}
9
9
    <style>
10
10
    td {
+
11
        display: table;
+
12
    }
+
13
    td {
11
14
    padding-right: 1em;
12
15
    }
13
16
    </style>
14
17
{% endblock stylesheets %}
15
18
16
19
{% block description %}
17
20
{{repository_description}}
18
21
{% endblock description %}
19
22
20
23
{% block header %}
21
24
<header>
22
25
    <label for="nav-drawer-toggle"></label>
23
26
    <h1>{{ repository_name }}</h1>  
24
27
</header>
25
28
{% endblock header %}
26
29
27
30
{% block nav %}
28
31
<input id="nav-drawer-toggle" type="checkbox" />
29
32
<nav>
30
33
    <label for="nav-drawer-toggle">🡠</label>
31
34
    <h2>{{ repository_name }}</h2>
32
35
    <a class="nav-link" href="{% url 'gitar-index' %}">Gitar | Index</a>
33
36
    <a class="nav-link" href="{% url 'about-index' %}">{% translate "Front page" %}</a>
34
37
    {% if subdirectories %}
35
38
    <hr class="half">
36
39
    {% endif %}
37
40
    {% for subdirectory in subdirectories %}
38
41
        <a class="nav-link" href="{% url 'gitar-path-explorer' repository_name branch subdirectory.path %}">
39
42
            {{ subdirectory.name }}
40
43
        </a>
41
44
    {% endfor %}
42
45
    <hr class="half">
43
46
    {% for file in files %}
44
47
        <a class="nav-link" href="{% url 'gitar-path-explorer' repository_name branch file.path %}">
45
48
        {{ file.name }}
46
49
        </a>
47
50
    {% endfor %}
48
51
</nav>
49
52
{% endblock nav %}
50
53
51
54
{% block main %}
52
55
<aside>
53
56
    <!-- Add tertiary information such as branches and licensing here.  -->
54
57
    <h2>{{repository_name}}</h2>
55
58
    <p>{{ repository_description }}</p>
56
59
    <h3>{% trans "Branches" %}</h3>
57
60
    {% for bbranch in branches %}
58
61
    <a href="{% url 'gitar-repository' repository_name bbranch %}">
59
62
        {{ bbranch }}
60
63
    </a><br>
61
64
    {% endfor %}
62
65
    {% comment %}<h5 class="{{mdc}}-text">{% trans "Extra information" %}</h5>
63
66
    <div class="chip">
64
67
        {{repository_language}}
65
68
        <i class="material-icons {{mdac}}-text text-accent-3">code</i>
66
69
    </div><br />
67
70
    <div class="chip">
68
71
        {{repository_license}}
69
72
        <i class="material-icons {{mdac}}-text text-accent-3">copyright</i>
70
73
    </div>
71
74
    {% endcomment %}
72
75
</aside>
73
76
<section>
74
77
    <h2>{% translate "Content" %}</h2>
75
78
    <!--Tree contents-->
76
79
    <!-- Subdirectories -->
77
80
    {% if subdirectories %}
78
81
    <table>
79
82
        <thead>
80
83
            <tr>
81
84
                <th scope="col">{% translate "Subdirectories" %}</th>
82
85
            </tr>
83
86
        </thead>
84
87
        <tbody>
85
88
            {% for subdirectory in subdirectories %}
86
89
            <tr>
87
90
                <th>
88
91
                <a href="{% url 'gitar-path-explorer' repository_name branch subdirectory.path %}">
89
92
                    {{subdirectory.name}}
90
93
                </a>
91
94
                </th>
92
95
            </tr>
93
96
            {% endfor %}
94
97
        </tbody>
95
98
    </table>
96
99
    {% endif %}
97
100
    <!-- Files -->
98
101
    <table>
99
102
        <thead>
100
103
            <tr>
101
104
                <th scope="col">{% translate "File name" %}</th>
102
105
                <th scope="col">{% translate "Latest commit" %}</th>
103
106
                <th scope="col">{% translate "Latest update" %}</th>
104
107
            </tr>
105
108
        </thead>
106
109
        <tbody>
107
110
            {% for file in files %}
108
111
            <tr>
109
112
                <td><a href="{% url 'gitar-path-explorer' repository_name branch file.path %}">
110
113
                    {{ file.name }}</a></td>
111
114
                <td><a href="{% url 'gitar-commit' repository_name file.commit.hash %}">
112
115
                    {{ file.commit.msg|truncatewords_html:10 }}</a></td>
113
116
                <td>{% if file.older_than_one_month %}
114
117
                    {{ file.commit.committer_date|date }}
115
118
                    {% else %}
116
119
                    {{ file.commit.committer_date|naturaltime }}
117
120
                    {% endif %}
118
121
                    </td>
119
122
            </tr>
120
123
            {% endfor %}
121
124
        </tbody>
122
125
    </table>
123
126
    <!-- Commits -->
124
127
    <h2>{% translate "Commits" %}</h2>
125
128
    <table>
126
129
        <thead>
127
130
            <tr>
128
131
                <th scope="col">{% translate "Hash" %}</th>
129
132
                <th scope="col">{% translate "Author" %}</th>
130
133
                <th scope="col">{% translate "Description" %}</th>
131
134
                <th scope="col">{% translate "Date" %}</th>
132
135
            </tr>
133
136
        </thead>
134
137
        <tbody>
135
138
            {% for commit in commits %}
136
139
            <tr>
137
140
            <td><a href="{% url 'gitar-commit' repository_name commit.hash %}">
138
141
                <code>{{ commit.hash|truncatechars:15 }}</code>
139
142
            </a></td>
140
143
            <td>{{ commit.author|truncatewords:2 }}</td>
141
144
            <td>
142
145
                {{ commit.description|lower|capfirst|truncatewords:10|truncatechars:80 }}{% if commit.description|last != "." %}.{% endif %}
143
146
            </td>
144
147
            <td>{{ commit.date|date:"SHORT_DATETIME_FORMAT" }}</td>
145
148
            {% endfor %}
146
149
        </tbody>
147
150
    </table>
148
151
</section>
149
152
{% endblock main %}
150
153