Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Would like to embed diff-lcs such that it yields a html diff as a string #41

Open
bwl21 opened this issue May 19, 2017 · 6 comments
Open
Labels

Comments

@bwl21
Copy link

bwl21 commented May 19, 2017

I currently use

rawDiff     = Diffy::Diff.new(other.trace_orig, self.trace_orig)
diff_as_html=rawDiff.to_s(:html)

But diffy calls another executable. In our case we use ldiff as provided by liff-lcs.

I wanted to achieve something like

diff_as_html=diffs = Diff::LCS.htmldiff('foo', 'bfoobar')

which should yield

"<div class=\"diff\">\n  <ul>\n    <li class=\"del\"><del>foo</del></li>\n    <li class=\"ins\"><ins>foo<strong>bar</strong></ins></li>\n  </ul>\n</div>\n"

How can I achieve this?

@bwl21 bwl21 changed the title Would like to embedd diff-cls such that it yields a html diff Would like to embedd diff-lcs such that it yields a html diff as a string May 19, 2017
@halostatue halostatue changed the title Would like to embedd diff-lcs such that it yields a html diff as a string Would like to embed diff-lcs such that it yields a html diff as a string May 20, 2017
@halostatue
Copy link
Owner

So…I’m not 100% sure, to be honest. I don't see adding an htmldiff method the way you’ve written its suggested output (I don’t agree with the <ul>/<li> output), but there is a class, Diff::LCS::HTMLDiff which may lead you in the direction you are after creating. You’d end up creating the appropriate callbacks to put the sort of output you want.

@bwl21
Copy link
Author

bwl21 commented May 20, 2017

Just to explain the context. I have a bunch of text snippets ( in particular a bunch of requirement spec items), and I want to generate an HTML file which shows the difference between the two versions as a table with one row per spec item. The styling of the difference is done by css.

I don't care if it uses li or div or whatever as long as I can style it properly. As of now, I use, what Diffy provides.

I managed to somehow use Diff::LCS::HTMLDiff but it seems to be not close to what I want:

  1. I have to provide an array of characters instead of strings - well thats possible
  2. I only get the diff on character level, not on lines as well

so I think I will try to add another method to Diffy (Diffy.diff_noshell) and replace the code that calls the external diff command by some code from ldiff.rb.

There is a related issue there samg/diffy#63.

So we can close this if you do not want to provide a htmldiff method.

@halostatue
Copy link
Owner

I’m not against the idea of an htmldiff method as such, but I’d rather work on something that makes the whole toolkit easier to use—because the styling and choices that people would make for how they show a diff in HTML will be different for every person and use case. What I’m suggesting is to look at the implementations of both ldiff and htmldiff (which are in Diff::LCS::Ldiff and Diff::LCS::HTMLDiff) respectively to implement it as you have suggested. I’m more than happy to work through your implementation and from that we may be able to figure out a way to have an htmldiff method that provides an HTML-structured diff output that allows for deep customization (and, in the process, improve the existing htmldiff program which is pretty crappy, IMO).

@bwl21
Copy link
Author

bwl21 commented Jul 7, 2017

I went in to the thing again and found a solution which works for me. As it is not generic I cannot prepare a pull request.
But it might be of interest. I copy it from my rspec

describe "arhtmldiff" do
  it "calls sdiff" do
    require 'diff/lcs'

    class Callbacks
      attr_accessor :output

      def initialize(output, options = {})
        @output = output
        @state  = :init
        options ||= {}

        @styles={
            ins: "text-decoration: underline;color:blue;",
            del: "text-decoration: line-through;color:red;",
            eq: ""
        }
      end

      def to_html(element)
        element #.gsub(/./, {'<' => '&lt;', '>' => '&gt;', '&' => '&amp;'})
      end

      def handle_entry(element, state)
        #binding.pry
        unless @state == state
          @output.push "</span>" unless @state == :init
          @state = state
          @output.push %Q{<span style="#{@styles[state]}">}
        end

        @output.push(to_html(element))
      end

      private :handle_entry

      # This will be called with both lines are the same
      def match(event)
        handle_entry(event.old_element, :eq)
      end

      # This will be called when there is a line in A that isn't in B
      def discard_a(event)
        handle_entry(event.old_element, :del)
      end

      # This will be called when there is a line in B that isn't in A
      def discard_b(event)
        handle_entry(event.new_element, :ins)
      end
    end


    data_old = %q{
foo
bar}
    data_new = %q{
boo
far
and more
}

    output = []

    output.push %Q{<pre>}

    callback_obj = Callbacks.new(output)
    xx           = Diff::LCS.traverse_sequences(data_old, data_new, callback_obj)

    output.push %Q{</pre>}
    puts output.join

    expect(output.join).to eq %q{<pre><span style="">
</span><span style="text-decoration: line-through;color:red;">f</span><span style="text-decoration: underline;color:blue;">b</span><span style="">oo
</span><span style="text-decoration: line-through;color:red;">b</span><span style="text-decoration: underline;color:blue;">f</span><span style="">ar</span><span style="text-decoration: underline;color:blue;">
and more
</pre>}

  end
end

@halostatue
Copy link
Owner

Thanks. I’ll look this over to see if I can extract something common.

@mtomov
Copy link

mtomov commented Oct 10, 2022

Thanks @bwl21 - that was very useful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants