Skip to content
This repository has been archived by the owner on Dec 31, 2024. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: deltadoc/text_delta
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.2.0
Choose a base ref
...
head repository: deltadoc/text_delta
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Jun 8, 2017

  1. Copy the full SHA
    8cf9e46 View commit details

Commits on Nov 30, 2017

  1. Copy the full SHA
    2a5dc8d View commit details

Commits on Dec 28, 2017

  1. Bump dependencies

    everzet committed Dec 28, 2017
    Copy the full SHA
    52452de View commit details
  2. Copy the full SHA
    ec16f5b View commit details
  3. Add TextDelta.lines

    everzet committed Dec 28, 2017
    Copy the full SHA
    5366446 View commit details
  4. Test TextDelta.lines!

    everzet committed Dec 28, 2017
    Copy the full SHA
    71de365 View commit details
  5. Merge pull request #4 from sroze/patch-1

    Fix a minor typo
    everzet authored Dec 28, 2017
    Copy the full SHA
    7832678 View commit details

Commits on Dec 29, 2017

  1. Copy the full SHA
    cd907a3 View commit details
  2. Implement TextDelta.diff

    everzet committed Dec 29, 2017
    Copy the full SHA
    f72a618 View commit details
  3. Copy the full SHA
    5bdc1db View commit details
  4. Bump version

    everzet committed Dec 29, 2017
    Copy the full SHA
    bff8adf View commit details

Commits on Apr 2, 2018

  1. Copy the full SHA
    bd343e5 View commit details
  2. Copy the full SHA
    823bb90 View commit details
  3. Bump to 1.6 minimum

    everzet committed Apr 2, 2018
    Copy the full SHA
    3a387e2 View commit details
  4. Copy the full SHA
    30d3bd1 View commit details

Commits on May 29, 2018

  1. Bump dependencies

    everzet committed May 29, 2018
    Copy the full SHA
    fa6545b View commit details

Commits on Jun 9, 2018

  1. Introduce compose example

    Useful for profiling in particular
    everzet committed Jun 9, 2018
    Copy the full SHA
    2c54a4f View commit details
  2. Optimise slightly the iterator

    Avoid unnecessary String.length calls as these are very expensive
    everzet committed Jun 9, 2018
    Copy the full SHA
    45ac09f View commit details
  3. Copy the full SHA
    3f3761b View commit details
  4. Fix linting errors

    everzet committed Jun 9, 2018
    Copy the full SHA
    612f29a View commit details
  5. Bump the application version

    everzet committed Jun 9, 2018
    Copy the full SHA
    a37ccbc View commit details
8 changes: 8 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
inputs: [
"{lib,test}/**/*.{ex,exs}",
"mix.exs",
".formatter.exs"
],
line_length: 80
]
9 changes: 7 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
language: elixir
sudo: false

elixir: [1.4.4]
otp_release: 19.3
elixir:
- 1.6

otp_release:
- 19.3
- 20.1

cache:
directories:
@@ -12,5 +16,6 @@ before_script:
- mix eqc.install --mini || true

script:
- mix format --check-formatted
- mix test
- mix credo --strict
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [1.4.0] - 2018-06-09
### Added
- Introduced experimental support for disabling unicode support through
`:text_delta.support_unicode` config. This is useful, because disabling
grapheme handling drastically speeds up all string operations (used heavily).
If you implementation does not need support of unicode, using this config
can greatly improve performance of the library.

### Fixed
- Small performance optimisations by avoiding unnecessary `String.length`
calls

## [1.3.0] - 2017-12-29
### Added
- `&TextDelta.lines/1` and `&TextDelta.lines!/1`
- `&TextDelta.diff/2` and `&TextDelta.diff!/2`

## [1.2.0] - 2017-05-29
### Added
- `&TextDelta.apply/2` and `&TextDelta.apply!/2`
@@ -56,7 +73,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Attributes support in `insert` and `retain`
- Delta composition and transformation with attributes supported

[Unreleased]: https://github.com/everzet/text_delta/compare/v1.2.0...HEAD
[Unreleased]: https://github.com/everzet/text_delta/compare/v1.4.0...HEAD
[1.4.0]: https://github.com/everzet/text_delta/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/everzet/text_delta/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/everzet/text_delta/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/everzet/text_delta/compare/v1.0.2...v1.1.0
[1.0.2]: https://github.com/everzet/text_delta/compare/v1.0.1...v1.0.2
4 changes: 4 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use Mix.Config

config :text_delta,
support_unicode: true
41 changes: 27 additions & 14 deletions lib/text_delta.ex
Original file line number Diff line number Diff line change
@@ -48,11 +48,15 @@ defmodule TextDelta do
[quill]: https://quilljs.com
"""

alias TextDelta.{Operation,
Attributes,
Composition,
Transformation,
Application}
alias TextDelta.{
Operation,
Attributes,
Composition,
Transformation,
Application,
Document,
Difference
}

defstruct ops: []

@@ -61,13 +65,13 @@ defmodule TextDelta do
`t:TextDelta.Operation.insert/0`, or `t:TextDelta.Operation.delete/0`
operations.
"""
@type t :: %TextDelta{ops: [Operation.t]}
@type t :: %TextDelta{ops: [Operation.t()]}

@typedoc """
A text state represented as delta. Any text state can be represented as a set
of `t:TextDelta.Operation.insert/0` operations.
"""
@type state :: %TextDelta{ops: [Operation.insert]}
@type state :: %TextDelta{ops: [Operation.insert()]}

@typedoc """
Alias to `t:TextDelta.state/0`.
@@ -87,7 +91,7 @@ defmodule TextDelta do
iex> TextDelta.new([TextDelta.Operation.insert("hello")])
%TextDelta{ops: [%{insert: "hello"}]}
"""
@spec new([Operation.t]) :: t
@spec new([Operation.t()]) :: t
def new(ops \\ [])
def new([]), do: %TextDelta{}
def new(ops), do: Enum.reduce(ops, new(), &append(&2, &1))
@@ -106,7 +110,7 @@ defmodule TextDelta do
iex> TextDelta.insert(TextDelta.new(), "hello", %{bold: true})
%TextDelta{ops: [%{insert: "hello", attributes: %{bold: true}}]}
"""
@spec insert(t, Operation.element, Attributes.t) :: t
@spec insert(t, Operation.element(), Attributes.t()) :: t
def insert(delta, el, attrs \\ %{}) do
append(delta, Operation.insert(el, attrs))
end
@@ -125,7 +129,7 @@ defmodule TextDelta do
iex> TextDelta.retain(TextDelta.new(), 5, %{italic: true})
%TextDelta{ops: [%{retain: 5, attributes: %{italic: true}}]}
"""
@spec retain(t, non_neg_integer, Attributes.t) :: t
@spec retain(t, non_neg_integer, Attributes.t()) :: t
def retain(delta, len, attrs \\ %{}) do
append(delta, Operation.retain(len, attrs))
end
@@ -164,7 +168,7 @@ defmodule TextDelta do
iex> TextDelta.append(TextDelta.new(), operation)
%TextDelta{ops: [%{insert: "hello"}]}
"""
@spec append(t, Operation.t) :: t
@spec append(t, Operation.t()) :: t
def append(delta, op) do
delta.ops
|> Enum.reverse()
@@ -177,6 +181,10 @@ defmodule TextDelta do
defdelegate transform(left, right, priority), to: Transformation
defdelegate apply(state, delta), to: Application
defdelegate apply!(state, delta), to: Application
defdelegate lines(delta), to: Document
defdelegate lines!(delta), to: Document
defdelegate diff(first, second), to: Difference
defdelegate diff!(first, second), to: Difference

@doc """
Trims trailing retains from the end of a given delta.
@@ -189,14 +197,17 @@ defmodule TextDelta do
@spec trim(t) :: t
def trim(delta)
def trim(%TextDelta{ops: []} = empty), do: empty

def trim(delta) do
last_operation = List.last(delta.ops)

case Operation.trimmable?(last_operation) do
true ->
delta.ops
|> Enum.slice(0..-2)
|> wrap()
|> trim()

false ->
delta
end
@@ -218,7 +229,7 @@ defmodule TextDelta do
iex> TextDelta.length(TextDelta.new([%{insert: "hi"}]), [:retain])
0
"""
@spec length(t, [Operation.type]) :: non_neg_integer
@spec length(t, [Operation.type()]) :: non_neg_integer
def length(delta, op_types \\ [:insert, :retain, :delete]) do
delta.ops
|> Enum.filter(&(Operation.type(&1) in op_types))
@@ -234,7 +245,7 @@ defmodule TextDelta do
iex> TextDelta.operations(TextDelta.new([%{delete: 5}, %{retain: 3}]))
[%{delete: 5}, %{retain: 3}]
"""
@spec operations(t) :: [Operation.t]
@spec operations(t) :: [Operation.t()]
def operations(delta), do: delta.ops

defp compact(ops, %{insert: ""}), do: ops
@@ -245,7 +256,9 @@ defmodule TextDelta do
defp compact([], new_op), do: [new_op]

defp compact([%{delete: _} = del | ops_remainder], %{insert: _} = ins) do
compact(compact(ops_remainder, ins), del)
ops_remainder
|> compact(ins)
|> compact(del)
end

defp compact([last_op | ops_remainder], new_op) do
12 changes: 8 additions & 4 deletions lib/text_delta/application.ex
Original file line number Diff line number Diff line change
@@ -23,8 +23,9 @@ defmodule TextDelta.Application do
An ok/error tuple. Represents either a successful application in form of
`{:ok, new_state}` or an error in form of `{:error, reason}`.
"""
@type result :: {:ok, TextDelta.state}
| {:error, error_reason}
@type result ::
{:ok, TextDelta.state()}
| {:error, error_reason}

@doc """
Applies given delta to a particular text state, resulting in a new state.
@@ -49,11 +50,12 @@ defmodule TextDelta.Application do
iex> TextDelta.apply(doc, TextDelta.delete(TextDelta.new(), 5))
{:error, :length_mismatch}
"""
@spec apply(TextDelta.state, TextDelta.t) :: result
@spec apply(TextDelta.state(), TextDelta.t()) :: result
def apply(state, delta) do
case delta_within_text_length?(delta, state) do
true ->
{:ok, TextDelta.compose(state, delta)}

false ->
{:error, :length_mismatch}
end
@@ -65,11 +67,13 @@ defmodule TextDelta.Application do
Equivalent to `&TextDelta.Application.apply/2`, but instead of returning
ok/error tuples returns a new state or raises a `RuntimeError`.
"""
@spec apply!(TextDelta.state, TextDelta.t) :: TextDelta.state | no_return
@spec apply!(TextDelta.state(), TextDelta.t()) ::
TextDelta.state() | no_return
def apply!(state, delta) do
case __MODULE__.apply(state, delta) do
{:ok, new_state} ->
new_state

{:error, reason} ->
raise "Can not apply delta to state: #{Atom.to_string(reason)}"
end
40 changes: 40 additions & 0 deletions lib/text_delta/attributes.ex
Original file line number Diff line number Diff line change
@@ -63,6 +63,31 @@ defmodule TextDelta.Attributes do
|> remove_nils()
end

@doc """
Calculates and returns difference between two sets of attributes.
Given an initial set of attributes and the final one, this function will
generate an attribute set that is when composed with original one would yield
the final result.
## Examples
iex> TextDelta.Attributes.diff(%{font: "arial", color: "blue"},
iex> %{color: "red"})
%{font: nil, color: "red"}
"""
@spec diff(t, t) :: t
def diff(attrs_a, attrs_b)

def diff(nil, attrs_b), do: diff(%{}, attrs_b)
def diff(attrs_a, nil), do: diff(attrs_a, %{})

def diff(attrs_a, attrs_b) do
%{}
|> add_changes(attrs_a, attrs_b)
|> add_deletions(attrs_a, attrs_b)
end

@doc """
Transforms `right` attribute set against the `left` one.
@@ -96,6 +121,21 @@ defmodule TextDelta.Attributes do
remove_duplicates(right, left)
end

defp add_changes(result, from, to) do
to
|> Enum.filter(fn {key, val} -> Map.get(from, key) != val end)
|> Enum.into(%{})
|> Map.merge(result)
end

defp add_deletions(result, from, to) do
from
|> Enum.filter(fn {key, _} -> not Map.has_key?(to, key) end)
|> Enum.map(fn {key, _} -> {key, nil} end)
|> Enum.into(%{})
|> Map.merge(result)
end

defp remove_nils(result) do
result
|> Enum.filter(fn {_, v} -> not is_nil(v) end)
Loading