Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
8dfad143
Commit
8dfad143
authored
Jan 14, 2016
by
Douwe Maan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add inline diff markers in highlighted diffs.
parent
83e4fc18
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
187 additions
and
40 deletions
+187
-40
app/controllers/projects/blob_controller.rb
app/controllers/projects/blob_controller.rb
+1
-1
app/views/projects/diffs/_parallel_view.html.haml
app/views/projects/diffs/_parallel_view.html.haml
+2
-2
app/views/projects/diffs/_text_file.html.haml
app/views/projects/diffs/_text_file.html.haml
+1
-1
lib/gitlab/diff/file.rb
lib/gitlab/diff/file.rb
+1
-1
lib/gitlab/diff/highlight.rb
lib/gitlab/diff/highlight.rb
+173
-33
lib/gitlab/highlight.rb
lib/gitlab/highlight.rb
+7
-0
spec/lib/gitlab/diff/highlight_spec.rb
spec/lib/gitlab/diff/highlight_spec.rb
+2
-2
No files found.
app/controllers/projects/blob_controller.rb
View file @
8dfad143
...
...
@@ -66,7 +66,7 @@ class Projects::BlobController < Projects::ApplicationController
def
diff
@form
=
UnfoldForm
.
new
(
params
)
@lines
=
Gitlab
::
Diff
::
Highlight
.
process_file
(
repository
,
@ref
,
@path
)
@lines
=
Gitlab
::
Highlight
.
highlight_lines
(
repository
,
@ref
,
@path
)
@lines
=
@lines
[
@form
.
since
-
1
..
@form
.
to
-
1
]
if
@form
.
bottom?
...
...
app/views/projects/diffs/_parallel_view.html.haml
View file @
8dfad143
...
...
@@ -13,7 +13,7 @@
=
link_to
raw
(
left
[
:number
]),
"#
#{
left
[
:line_code
]
}
"
,
id:
left
[
:line_code
]
-
if
@comments_allowed
&&
can?
(
current_user
,
:create_note
,
@project
)
=
link_to_new_diff_note
(
left
[
:line_code
],
'old'
)
%td
.line_content
{
class:
"parallel noteable_line #{left[:type]} #{left[:line_code]}"
,
"line_code"
=>
left
[
:line_code
]
}=
diff_line_content
(
left
[
:text
])
%td
.line_content
{
class:
"parallel noteable_line #{left[:type]} #{left[:line_code]}"
,
data:
{
"line_code"
=>
left
[
:line_code
]
}
}=
diff_line_content
(
left
[
:text
])
-
if
right
[
:type
]
==
'new'
-
new_line_class
=
'new'
...
...
@@ -26,7 +26,7 @@
=
link_to
raw
(
right
[
:number
]),
"#
#{
new_line_code
}
"
,
id:
new_line_code
-
if
@comments_allowed
&&
can?
(
current_user
,
:create_note
,
@project
)
=
link_to_new_diff_note
(
right
[
:line_code
],
'new'
)
%td
.line_content.parallel
{
class:
"noteable_line #{new_line_class} #{new_line_code}"
,
"line_code"
=>
new_line_code
}=
diff_line_content
(
right
[
:text
])
%td
.line_content.parallel
{
class:
"noteable_line #{new_line_class} #{new_line_code}"
,
data:
{
"line_code"
=>
new_line_code
}
}=
diff_line_content
(
right
[
:text
])
-
if
@reply_allowed
-
comments_left
,
comments_right
=
organize_comments
(
left
[
:type
],
right
[
:type
],
left
[
:line_code
],
right
[
:line_code
])
...
...
app/views/projects/diffs/_text_file.html.haml
View file @
8dfad143
...
...
@@ -22,7 +22,7 @@
=
link_to_new_diff_note
(
line_code
)
%td
.new_line
{
data:
{
linenumber:
line
.
new_pos
}}
=
link_to
raw
(
type
==
"old"
?
" "
:
line
.
new_pos
),
"#
#{
line_code
}
"
,
id:
line_code
%td
.line_content
{
class:
"noteable_line #{type} #{line_code}"
,
"line_code"
=>
line_code
}=
diff_line_content
(
line
.
text
)
%td
.line_content
{
class:
"noteable_line #{type} #{line_code}"
,
data:
{
"line_code"
=>
line_code
}
}=
diff_line_content
(
line
.
text
)
-
if
@reply_allowed
-
comments
=
@line_notes
.
select
{
|
n
|
n
.
line_code
==
line_code
&&
n
.
active?
}.
sort_by
(
&
:created_at
)
...
...
lib/gitlab/diff/file.rb
View file @
8dfad143
...
...
@@ -18,7 +18,7 @@ module Gitlab
end
def
highlighted_diff_lines
Gitlab
::
Diff
::
Highlight
.
process_diff_lines
(
self
)
Gitlab
::
Diff
::
Highlight
.
new
(
self
).
highlight
end
def
mode_changed?
...
...
lib/gitlab/diff/highlight.rb
View file @
8dfad143
...
...
@@ -6,59 +6,199 @@ module Gitlab
delegate
:repository
,
:old_path
,
:new_path
,
:old_ref
,
:new_ref
,
to: :diff_file
,
prefix: :diff
# Apply syntax highlight to provided source code
#
# diff_file - an instance of Gitlab::Diff::File
#
# Returns an Array with the processed items.
def
self
.
process_diff_lines
(
diff_file
)
processor
=
new
(
diff_file
)
processor
.
highlight
def
initialize
(
diff_file
)
@diff_file
=
diff_file
@diff_lines
=
diff_file
.
diff_lines
@raw_lines
=
@diff_lines
.
map
(
&
:text
)
end
def
self
.
process_file
(
repository
,
ref
,
file_name
)
blob
=
repository
.
blob_at
(
ref
,
file_name
)
return
[]
unless
blob
def
highlight
return
[]
if
@diff_lines
.
empty?
Gitlab
::
Highlight
.
highlight
(
file_name
,
blob
.
data
).
lines
.
map!
(
&
:html_safe
)
end
find_inline_diffs
def
initialize
(
diff_file
)
@diff_file
=
diff_file
@file_name
=
diff_file
.
new_path
@lines
=
diff_file
.
diff_lines
process_lines
@diff_lines
end
def
highlight
return
[]
if
@lines
.
empty?
private
@lines
.
each_with_index
do
|
line
,
i
|
line_prefix
=
line
.
text
.
match
(
/\A([+-])/
)
?
$1
:
' '
def
find_inline_diffs
@inline_diffs
=
[]
local_edit_indexes
.
each
do
|
index
|
old_index
=
index
new_index
=
index
+
1
old_line
=
@raw_lines
[
old_index
][
1
..-
1
]
new_line
=
@raw_lines
[
new_index
][
1
..-
1
]
# Skip inline diff if empty line was replaced with content
next
if
old_line
==
""
lcp
=
longest_common_prefix
(
old_line
,
new_line
)
lcs
=
longest_common_suffix
(
old_line
,
new_line
)
old_diff_range
=
lcp
..
(
old_line
.
length
-
lcs
-
1
)
new_diff_range
=
lcp
..
(
new_line
.
length
-
lcs
-
1
)
@inline_diffs
[
old_index
]
=
old_diff_range
if
old_diff_range
.
begin
<=
old_diff_range
.
end
@inline_diffs
[
new_index
]
=
new_diff_range
if
new_diff_range
.
begin
<=
new_diff_range
.
end
end
end
def
process_lines
@diff_lines
.
each_with_index
do
|
diff_line
,
i
|
# ignore highlighting for "match" lines
next
if
line
.
type
==
'match'
next
if
diff_line
.
type
==
'match'
rich_line
=
highlight_line
(
diff_line
,
i
)
rich_line
=
mark_inline_diffs
(
rich_line
,
diff_line
,
i
)
diff_line
.
text
=
rich_line
.
html_safe
end
end
def
highlight_line
(
diff_line
,
index
)
line_prefix
=
line_prefixes
[
index
]
case
diff_line
.
type
when
'new'
,
nil
rich_line
=
new_lines
[
diff_line
.
new_pos
-
1
]
when
'old'
rich_line
=
old_lines
[
diff_line
.
old_pos
-
1
]
end
# Only update text if line is found. This will prevent
# issues with submodules given the line only exists in diff content.
rich_line
?
line_prefix
+
rich_line
:
diff_line
.
text
end
def
mark_inline_diffs
(
rich_line
,
diff_line
,
index
)
inline_diff
=
@inline_diffs
[
index
]
return
rich_line
unless
inline_diff
raw_line
=
diff_line
.
text
# Based on the prefixless versions
from
=
inline_diff
.
begin
+
1
to
=
inline_diff
.
end
+
1
position_mapping
=
map_character_positions
(
raw_line
,
rich_line
)
inline_diff_positions
=
position_mapping
[
from
..
to
]
marker_ranges
=
collapse_ranges
(
inline_diff_positions
)
offset
=
0
marker_ranges
.
each
do
|
range
|
offset
=
insert_around_range
(
rich_line
,
range
,
"<span class='idiff'>"
,
"</span>"
,
offset
)
end
rich_line
end
case
line
.
type
when
'new'
,
nil
highlighted_line
=
new_lines
[
line
.
new_pos
-
1
]
when
'old'
highlighted_line
=
old_lines
[
line
.
old_pos
-
1
]
def
line_prefixes
@line_prefixes
||=
@raw_lines
.
map
{
|
line
|
line
.
match
(
/\A([+-])/
)
?
$1
:
' '
}
end
def
local_edit_indexes
@local_edit_indexes
||=
begin
joined_line_prefixes
=
"
#{
line_prefixes
.
join
}
"
offset
=
0
local_edit_indexes
=
[]
while
index
=
joined_line_prefixes
.
index
(
" -+ "
,
offset
)
local_edit_indexes
<<
index
offset
=
index
+
1
end
# Only update text if line is found. This will prevent
# issues with submodules given the line only exists in diff content.
line
.
text
=
highlighted_line
.
insert
(
0
,
line_prefix
).
html_safe
if
highlighted_line
local_edit_indexes
end
end
def
map_character_positions
(
raw_line
,
rich_line
)
mapping
=
[]
raw_pos
=
0
rich_pos
=
0
(
0
..
raw_line
.
length
).
each
do
|
raw_pos
|
raw_char
=
raw_line
[
raw_pos
]
rich_char
=
rich_line
[
rich_pos
]
while
rich_char
==
'<'
until
rich_char
==
'>'
rich_pos
+=
1
rich_char
=
rich_line
[
rich_pos
]
end
rich_pos
+=
1
rich_char
=
rich_line
[
rich_pos
]
end
@lines
mapping
[
raw_pos
]
=
rich_pos
rich_pos
+=
1
end
mapping
end
def
old_lines
@old_lines
||=
self
.
class
.
process_file
(
diff_repository
,
diff_old_ref
,
diff_old_path
)
@old_lines
||=
Gitlab
::
Highlight
.
highlight_lines
(
diff_repository
,
diff_old_ref
,
diff_old_path
)
end
def
new_lines
@new_lines
||=
self
.
class
.
process_file
(
diff_repository
,
diff_new_ref
,
diff_new_path
)
@new_lines
||=
Gitlab
::
Highlight
.
highlight_lines
(
diff_repository
,
diff_new_ref
,
diff_new_path
)
end
def
longest_common_suffix
(
a
,
b
)
longest_common_prefix
(
a
.
reverse
,
b
.
reverse
)
end
def
longest_common_prefix
(
a
,
b
)
max_length
=
[
a
.
length
,
b
.
length
].
max
length
=
0
(
0
..
max_length
-
1
).
each
do
|
pos
|
old_char
=
a
[
pos
]
new_char
=
b
[
pos
]
break
if
old_char
!=
new_char
length
+=
1
end
length
end
def
collapse_ranges
(
positions
)
return
[]
if
positions
.
empty?
ranges
=
[]
start
=
prev
=
positions
[
0
]
range
=
start
..
prev
positions
[
1
..-
1
].
each
do
|
pos
|
if
pos
==
prev
+
1
range
=
start
..
pos
prev
=
pos
else
ranges
<<
range
start
=
prev
=
pos
range
=
start
..
prev
end
end
ranges
<<
range
ranges
end
def
insert_around_range
(
text
,
range
,
before
,
after
,
offset
=
0
)
from
=
range
.
begin
to
=
range
.
end
text
.
insert
(
offset
+
from
,
before
)
offset
+=
before
.
length
text
.
insert
(
offset
+
to
+
1
,
after
)
offset
+=
after
.
length
offset
end
end
end
...
...
lib/gitlab/highlight.rb
View file @
8dfad143
...
...
@@ -7,6 +7,13 @@ module Gitlab
formatter
.
format
(
lexer
.
lex
(
blob_content
,
continue:
continue
)).
html_safe
end
def
self
.
highlight_lines
(
repository
,
ref
,
file_name
)
blob
=
repository
.
blob_at
(
ref
,
file_name
)
return
[]
unless
blob
highlight
(
file_name
,
blob
.
data
).
lines
.
map!
(
&
:html_safe
)
end
private
def
self
.
rouge_formatter
(
options
=
{})
...
...
spec/lib/gitlab/diff/highlight_spec.rb
View file @
8dfad143
...
...
@@ -51,9 +51,9 @@ describe Gitlab::Diff::Highlight, lib: true do
end
end
describe
'.
process_file
'
do
describe
'.
highlight_lines
'
do
let
(
:lines
)
do
Gitlab
::
Diff
::
Highlight
.
process_file
(
project
.
repository
,
commit
.
id
,
'files/ruby/popen.rb'
)
Gitlab
::
Diff
::
Highlight
.
highlight_lines
(
project
.
repository
,
commit
.
id
,
'files/ruby/popen.rb'
)
end
it
'should properly highlight all the lines'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment