@@ -153,35 +153,10 @@ defmodule Code.Fragment do
153153 | { :dot , inside_dot , charlist }
154154 def cursor_context ( fragment , opts \\ [ ] )
155155
156- def cursor_context ( binary , opts ) when is_binary ( binary ) and is_list ( opts ) do
157- # CRLF not relevant here - we discard everything before last `\n`
158- binary = last_line ( binary )
159- # case :binary.matches(binary, "\n") do
160- # [] ->
161- # binary
162-
163- # matches ->
164- # {position, _} = List.last(matches)
165- # binary_part(binary, position + 1, byte_size(binary) - position - 1)
166- # end
167-
168- binary
169- |> String . to_charlist ( )
170- |> :lists . reverse ( )
171- |> codepoint_cursor_context ( opts )
172- |> elem ( 0 )
173- end
174-
175- def cursor_context ( charlist , opts ) when is_list ( charlist ) and is_list ( opts ) do
176- # CRLF not relevant here - we discard everything before last `\n`
177- # charlist =
178- # case charlist |> Enum.chunk_by(&(&1 == ?\n)) |> List.last([]) do
179- # [?\n | _] -> []
180- # rest -> rest
181- # end
182-
183- charlist
184- |> last_line
156+ def cursor_context ( fragment , opts )
157+ when ( is_binary ( fragment ) or is_list ( fragment ) ) and is_list ( opts ) do
158+ fragment
159+ |> last_line ( )
185160 |> :lists . reverse ( )
186161 |> codepoint_cursor_context ( opts )
187162 |> elem ( 0 )
@@ -594,18 +569,19 @@ defmodule Code.Fragment do
594569 | { :dot , inside_dot , charlist }
595570 def surround_context ( fragment , position , options \\ [ ] )
596571
597- def surround_context ( string , { line , column } , opts ) when is_binary ( string ) or is_list ( string ) do
598- { binary , { lines_before_reversed_lengths , cursor_line_length , lines_after_lengths } } =
599- join_lines ( string , line , column )
572+ def surround_context ( string , { line , column } , opts )
573+ when ( is_binary ( string ) or is_list ( string ) ) and is_list ( opts ) do
574+ { charlist , lines_before_lengths , lines_current_and_after_lengths } =
575+ surround_line ( string , line , column )
600576
601- prepended_columns = Enum . sum ( lines_before_reversed_lengths )
577+ prepended_columns = Enum . sum ( lines_before_lengths )
602578
603- binary
604- |> String . to_charlist ( )
579+ charlist
605580 |> position_surround_context ( line , column + prepended_columns , opts )
606581 |> to_multiline_range (
607582 prepended_columns ,
608- { lines_before_reversed_lengths , cursor_line_length , lines_after_lengths }
583+ lines_before_lengths ,
584+ lines_current_and_after_lengths
609585 )
610586 end
611587
@@ -810,22 +786,13 @@ defmodule Code.Fragment do
810786 defp enum_reverse_at ( [ h | t ] , n , acc ) when n > 0 , do: enum_reverse_at ( t , n - 1 , [ h | acc ] )
811787 defp enum_reverse_at ( rest , _ , acc ) , do: { acc , rest }
812788
813- @ comment_strip ~r/ (?<!\< )\# (?!\{ ).*$/
814-
815789 defp last_line ( binary ) when is_binary ( binary ) do
816790 [ last_line | lines_reverse ] =
817791 binary
818792 |> String . split ( [ "\r \n " , "\n " ] )
819793 |> Enum . reverse ( )
820794
821- lines_reverse =
822- lines_reverse
823- |> Enum . map ( & Regex . replace ( @ comment_strip , & 1 , "" ) )
824-
825- last_line = last_line
826-
827- prepend_lines_before ( last_line , lines_reverse )
828- |> IO . chardata_to_string ( )
795+ prepend_cursor_lines ( lines_reverse , String . to_charlist ( last_line ) )
829796 end
830797
831798 defp last_line ( charlist ) when is_list ( charlist ) do
@@ -836,177 +803,128 @@ defmodule Code.Fragment do
836803 |> :string . split ( '\n ' , :all )
837804 |> Enum . reverse ( )
838805
839- lines_reverse =
840- lines_reverse
841- |> Enum . map ( & Regex . replace ( @ comment_strip , List . to_string ( & 1 ) , "" ) )
842-
843- last_line = last_line |> List . to_string ( )
844-
845- prepend_lines_before ( last_line , lines_reverse )
846- |> IO . chardata_to_string ( )
847- |> String . to_charlist ( )
848- end
849-
850- defp prepend_lines_before ( cursor_line , lines_before_reverse ) do
851- lines_before_reverse
852- |> Enum . reduce_while ( [ cursor_line ] , fn line , [ head | _ ] = acc ->
853- line_trimmed = String . trim ( line )
854- acc_trimmed = String . trim_leading ( head )
855-
856- if String . starts_with? ( acc_trimmed , "." ) or line_trimmed == "" or
857- String . ends_with? ( line_trimmed , "." ) or String . ends_with? ( line_trimmed , "(" ) do
858- { :cont , [ line | acc ] }
859- else
860- { :halt , acc }
861- end
862- end )
806+ prepend_cursor_lines ( lines_reverse , last_line )
863807 end
864808
865- defp append_lines_after ( cursor_line , lines_after ) do
866- lines_after
867- |> Enum . reduce_while ( [ cursor_line ] , fn line , [ head | _ ] = acc ->
868- line_trimmed = String . trim_leading ( line )
869- acc_trimmed = String . trim ( head )
870-
871- if String . starts_with? ( line_trimmed , "." ) or acc_trimmed == "" or
872- String . ends_with? ( acc_trimmed , "." ) or String . ends_with? ( acc_trimmed , "(" ) do
873- { :cont , [ line | acc ] }
874- else
875- { :halt , acc }
876- end
877- end )
878- |> Enum . reverse ( )
809+ defp prepend_cursor_lines ( lines , last_line ) do
810+ with [ line | lines ] <- lines ,
811+ { trimmed_line , incomplete? } = ends_as_incomplete ( to_charlist ( line ) , [ ] , true ) ,
812+ true <- incomplete? or starts_with_dot? ( last_line ) do
813+ prepend_cursor_lines ( lines , Enum . reverse ( trimmed_line , last_line ) )
814+ else
815+ _ -> last_line
816+ end
879817 end
880818
881- def join_lines ( binary , line , column ) when is_binary ( binary ) do
882- lines =
883- binary
884- |> String . split ( [ "\r \n " , "\n " ] )
885-
886- lines_before_reverse =
887- if line > 1 do
888- lines
889- |> Enum . slice ( 0 .. ( line - 2 ) )
890- |> Enum . reverse ( )
891- |> Enum . map ( & Regex . replace ( @ comment_strip , & 1 , "" ) )
892- else
893- [ ]
894- end
819+ defp starts_with_dot? ( [ ?. | _ ] ) , do: true
820+ defp starts_with_dot? ( [ h | t ] ) when h in @ space , do: starts_with_dot? ( t )
821+ defp starts_with_dot? ( _ ) , do: false
895822
896- lines_after =
897- lines
898- |> Enum . slice ( line .. - 1 )
899- |> Enum . map ( & Regex . replace ( @ comment_strip , & 1 , "" ) )
823+ defp ends_as_incomplete ( [ ?# | _ ] , acc , incomplete? ) ,
824+ do: { acc , incomplete? }
900825
901- cursor_line =
902- lines
903- |> Enum . at ( line - 1 )
826+ defp ends_as_incomplete ( [ h | t ] , acc , _incomplete? ) when h in [ ?( , ?. ] ,
827+ do: ends_as_incomplete ( t , [ h | acc ] , true )
904828
905- cursor_line_stripped = Regex . replace ( @ comment_strip , cursor_line , "" )
829+ defp ends_as_incomplete ( [ h | t ] , acc , incomplete? ) when h in @ space ,
830+ do: ends_as_incomplete ( t , [ h | acc ] , incomplete? )
906831
907- cursor_line_stripped =
908- if column - 1 > String . length ( cursor_line_stripped ) do
909- cursor_line
910- else
911- cursor_line_stripped
912- end
832+ defp ends_as_incomplete ( [ h | t ] , acc , _incomplete? ) ,
833+ do: ends_as_incomplete ( t , [ h | acc ] , false )
913834
914- added_before_lines = prepend_lines_before ( cursor_line_stripped , lines_before_reverse )
915- [ _ | added_after_lines ] = append_lines_after ( cursor_line_stripped , lines_after )
835+ defp ends_as_incomplete ( [ ] , acc , incomplete? ) ,
836+ do: { acc , incomplete? }
916837
917- built =
918- [ added_before_lines , added_after_lines ]
919- |> IO . chardata_to_string ( )
838+ defp surround_line ( binary , line , column ) when is_binary ( binary ) do
839+ binary
840+ |> String . split ( [ "\r \n " , "\n " ] )
841+ |> Enum . map ( & String . to_charlist / 1 )
842+ |> surround_lines ( line , column )
843+ end
920844
921- { built ,
922- { Enum . map ( lines_before_reverse , & String . length / 1 ) , String . length ( cursor_line_stripped ) ,
923- Enum . map ( lines_after , & String . length / 1 ) } }
845+ defp surround_line ( charlist , line , column ) when is_list ( charlist ) do
846+ charlist
847+ |> :string . replace ( '\r \n ' , '\n ' , :all )
848+ |> :string . join ( '' )
849+ |> :string . split ( '\n ' , :all )
850+ |> surround_lines ( line , column )
924851 end
925852
926- def join_lines ( charlist , line , column ) when is_list ( charlist ) do
927- lines =
928- charlist
929- |> :string . replace ( '\r \n ' , '\n ' , :all )
930- |> :string . join ( '' )
931- |> :string . split ( '\n ' , :all )
853+ defp surround_lines ( lines , line , column ) do
854+ { lines_before_reverse , cursor_line , lines_after } = split_at ( lines , line , [ ] )
855+ { trimmed_cursor_line , incomplete? } = ends_as_incomplete ( to_charlist ( cursor_line ) , [ ] , true )
932856
933- lines_before_reverse =
934- if line > 1 do
935- lines
936- |> Enum . slice ( 0 .. ( line - 2 ) )
937- |> Enum . reverse ( )
938- |> Enum . map ( & Regex . replace ( @ comment_strip , List . to_string ( & 1 ) , "" ) )
857+ reversed_cursor_line =
858+ if column - 1 > length ( trimmed_cursor_line ) do
859+ # Don't strip comments if cursor is inside a comment
860+ Enum . reverse ( cursor_line )
939861 else
940- [ ]
862+ trimmed_cursor_line
941863 end
942864
943- lines_after =
944- lines
945- |> Enum . slice ( line .. - 1 )
946- |> Enum . map ( & Regex . replace ( @ comment_strip , List . to_string ( & 1 ) , "" ) )
947-
948- cursor_line =
949- lines
950- |> Enum . at ( line - 1 )
951- |> List . to_string ( )
865+ { cursor_line , after_lengths } =
866+ append_surround_lines ( lines_after , [ ] , [ reversed_cursor_line ] , incomplete? )
952867
953- cursor_line_stripped = Regex . replace ( @ comment_strip , cursor_line , "" )
954-
955- cursor_line_stripped =
956- if column - 1 > String . length ( cursor_line_stripped ) do
957- # no comment strip if cursor is inside a comment
958- # we want to provide results inside comment
959- cursor_line
960- else
961- cursor_line_stripped
962- end
868+ { cursor_line , before_lengths } = prepend_surround_lines ( lines_before_reverse , [ ] , cursor_line )
869+ { cursor_line , before_lengths , [ length ( reversed_cursor_line ) | after_lengths ] }
870+ end
963871
964- added_before_lines = prepend_lines_before ( cursor_line_stripped , lines_before_reverse )
965- [ _ | added_after_lines ] = append_lines_after ( cursor_line_stripped , lines_after )
872+ defp split_at ( [ line ] , _ , acc ) , do: { acc , line , [ ] }
873+ defp split_at ( [ line | lines ] , 1 , acc ) , do: { acc , line , lines }
874+ defp split_at ( [ line | lines ] , count , acc ) , do: split_at ( lines , count - 1 , [ line | acc ] )
966875
967- built =
968- [ added_before_lines , added_after_lines ]
969- |> IO . chardata_to_string ( )
876+ defp prepend_surround_lines ( lines , lengths , last_line ) do
877+ with [ line | lines ] <- lines ,
878+ { trimmed_line , incomplete? } = ends_as_incomplete ( to_charlist ( line ) , [ ] , true ) ,
879+ true <- incomplete? or starts_with_dot? ( last_line ) do
880+ lengths = [ length ( trimmed_line ) | lengths ]
881+ prepend_surround_lines ( lines , lengths , Enum . reverse ( trimmed_line , last_line ) )
882+ else
883+ _ -> { last_line , Enum . reverse ( lengths ) }
884+ end
885+ end
970886
971- { built ,
972- { Enum . map ( lines_before_reverse , & String . length / 1 ) , String . length ( cursor_line_stripped ) ,
973- Enum . map ( lines_after , & String . length / 1 ) } }
887+ defp append_surround_lines ( lines , lengths , acc_lines , incomplete? ) do
888+ with [ line | lines ] <- lines ,
889+ line = to_charlist ( line ) ,
890+ true <- incomplete? or starts_with_dot? ( line ) do
891+ { trimmed_line , incomplete? } = ends_as_incomplete ( line , [ ] , true )
892+ lengths = [ length ( trimmed_line ) | lengths ]
893+ append_surround_lines ( lines , lengths , [ trimmed_line | acc_lines ] , incomplete? )
894+ else
895+ _ -> { Enum . reduce ( acc_lines , [ ] , & Enum . reverse / 2 ) , Enum . reverse ( lengths ) }
896+ end
974897 end
975898
976- defp to_multiline_range ( :none , _ , _ ) , do: :none
899+ defp to_multiline_range ( :none , _ , _ , _ ) , do: :none
977900
978901 defp to_multiline_range (
979902 % { begin: { begin_line , begin_column } , end: { end_line , end_column } } = context ,
980903 prepended ,
981- { lines_before_reversed_lengths , cursor_line_length , lines_after_lengths }
904+ lines_before_lengths ,
905+ lines_current_and_after_lengths
982906 ) do
983907 { begin_line , begin_column } =
984- lines_before_reversed_lengths
985- |> Enum . reduce_while ( { begin_line , begin_column - prepended } , fn line_length ,
986- { acc_line , acc_column } ->
987- if acc_column < 1 do
988- { :cont , { acc_line - 1 , acc_column + line_length } }
989- else
990- { :halt , { acc_line , acc_column } }
991- end
908+ Enum . reduce_while ( lines_before_lengths , { begin_line , begin_column - prepended } , fn
909+ line_length , { acc_line , acc_column } ->
910+ if acc_column < 1 do
911+ { :cont , { acc_line - 1 , acc_column + line_length } }
912+ else
913+ { :halt , { acc_line , acc_column } }
914+ end
992915 end )
993916
994917 { end_line , end_column } =
995- [ cursor_line_length | lines_after_lengths ]
996- |> Enum . reduce_while ( { end_line , end_column - prepended } , fn line_length ,
997- { acc_line , acc_column } ->
998- if acc_column > line_length + 1 do
999- { :cont , { acc_line + 1 , acc_column - line_length } }
1000- else
1001- { :halt , { acc_line , acc_column } }
1002- end
918+ Enum . reduce_while ( lines_current_and_after_lengths , { end_line , end_column - prepended } , fn
919+ line_length , { acc_line , acc_column } ->
920+ if acc_column > line_length + 1 do
921+ { :cont , { acc_line + 1 , acc_column - line_length } }
922+ else
923+ { :halt , { acc_line , acc_column } }
924+ end
1003925 end )
1004926
1005- context
1006- |> Map . merge ( % {
1007- begin: { begin_line , begin_column } ,
1008- end: { end_line , end_column }
1009- } )
927+ % { context | begin: { begin_line , begin_column } , end: { end_line , end_column } }
1010928 end
1011929
1012930 @ doc """
0 commit comments