-- require "strict"

--[[

NoteCase Pro script

   See http://www.notecasepro.com/

SCRIPT NAME: Join Lines

   Version 1.0.2 


PURPOSE: This script is intended to clean little messes such as clips from emails that have excess spaces and line breaks, reflowing the text. 

The script cannot be used on text that contains list markup and will abort prematurely with an error message if such markup is present. 

To use the script, select the text in the current note that you wish to clean and reflow, then launch the script. 

The script reformats one or more selected paragraphs that are separated by at least one blank line, removing any single line breaks and converting all tabs to spaces. 

After that processing, all multiple consecutive spaces are reduced to a single space and spaces at the beginning and ending of each paragraph are removed. 

At the end of the processing, the reformatted text replaces the selected text in the current note.  


CONFIGURATION: Recommended usage is with a keyboard shortcut or toolbar icon used as the launcher. See Help file > Automation, Scripts and Plugins > Launch Scripts and Plugin Actions Quicker. Recommended shortcut is Ctrl+J.


RIGHTS: This script's author, Paul E. Merrell, hereby waives all copyright and related or neighboring rights to this script, pursuant to the Creative Commons CC0 Universal relinquishment of rights found at http://creativecommons.org/publicdomain/zero/1.0/


CHANGE LOG:

v. 1.0.2

* refactored script so that it has no external dependencies

v. 1.0.1

* fix: add work-around for clips from Google Gmail, which places a non-break space between consecutive line breaks

--]]

function Get_Selected_Note_Content(nDocID, strNoteID, nIsHtml)

  -- get character offsets for selected text
  local nSelFrom, nSelTo = Nc_Note_SelectionRange_Get(nDocID, strNoteID)
assert(nSelFrom ~= nSelTo, [[
ERROR: Text must be selected 
in the Note Pane when using 
this script. Aborting execution.]])

  -- get user's selected content in scripter's desired format
  strContent = Nc_Note_Content_Get(nDocID, strNoteID, nIsHtml, nSelFrom, nSelTo)

  return strContent, nSelFrom, nSelTo

end -- function GetSelected


  -- load function to trim any trailing and leading whitespace
function trim(s)
  s = utf8ex.gsub(s, "^%s*(.-)%s*$", "%1")
 return s
end -- function


function Test_String_For_Substrings(s)
  tQueries = {
    "<UL>", "</UL>", "<LI>", "</LI>"}
  for i, v in ipairs(tQueries) do
    if utf8ex.find(s, v) ~= nil then
      return 0
    else
      return 1
    end -- if utf8ex.find
  end -- for i,
end -- function


function Make_String_One_Line(s)

  -- add any sub-strings or patterns to be replaced by a space to the following array. Note: any characters defined as white space by Lua (ANSI C) need not be included as they are replaced by the execution of the utf8ex.gsub line in the first following function, but that such characters may vary by locale
  local tReplace = {
    "<BR>", "<br>", "&nbsp;" 
  }

  -- replace excess whitespace with single space
  for i, v in pairs(tReplace) do
    s = utf8ex.gsub(s, v, " ")
  end -- whitespace replacement loop

  -- replace any non-space white space characters with space
  s = utf8ex.gsub(s, "%s+", " ")
  
  -- trim any leading and trailing whitespace
  s = trim(s)

 return s

end -- function


-- break string's lines into an array
function lines(s)
  local buf = {}
  for w in utf8ex.gmatch(s, "[^\n]+") do
    table.insert (buf, w)
  end -- for
  return buf
end


function JoinStringLines(s)

  -- work around Google Chrome/Gmail clipboard issue with insertion of non-breakspace between consecutive line breaks
  s = utf8ex.gsub(s, "<BR>\n&nbsp;<BR>","<BR>\n<BR>") 

  -- replace all occurrences of 3 consecutive line breaks trailed by newlines with token for later restoration
  s = utf8ex.gsub(s, "<BR>\n<BR>\n<BR>\n", "@~@")
	
  -- replace all occurrences of 2 consecutive line breaks trailed by newlines with token for later restoration
  s = utf8ex.gsub(s, "<BR>\n<BR>\n", "~@~")

  -- squish what's left into a single line
  s = Make_String_One_Line(s)

  -- restore three consecutive hard line breaks and their trailing newlines
  s = utf8ex.gsub(s, "@~@", "<BR>\n<BR>\n<BR>\n") 

  -- restore two consecutive hard line breaks with trailing newlines
  s = utf8ex.gsub(s, "~@~", "<BR>\n<BR>\n") 

  -- convert lines to table
  local buf = lines(s)

  -- set string to empty
  s = ""

  -- get number of lines in table
  nSize = #buf
 
   -- for each line, trim leading and trailing whitespaces and reassemble string
  for i=1, nSize do
    s = s .. trim(buf[i])
  end 

  return s

end -- function


function Replace_Selected_Note_Content(nDocID, strNoteID, strContent, nIsHtml, nSelFrom, nSelTo)

  -- make sure nSelFrom is <= SelTo
  if nSelFrom > nSelTo then nSelFrom, nSelTo = nSelTo, nSelFrom end

  -- replace the selected content in the note 
  Nc_Note_Content_Set(nDocID, strNoteID, strContent, nIsHtml, nSelFrom, nSelTo)

  -- get the character count of the new string
  local nCount = Nc_String_CharacterCount_Get(strContent)

  -- calculate new cursor offset
  local nCursorPos = nSelFrom + nCount 

  -- remove selection highlighting and set the cursor position immediately after the inserted new string
  Nc_Note_SelectionRange_Set(nDocID, strNoteID, nCursorPos, nCursorPos)

  return

end -- function

-- begin script

--get IDs of current document and note
local nDocID = Nc_Doc_ID_GetCur()
local strNoteID = Nc_Note_ID_GetCur(nDocID)

-- check to see if note is selected and abort the script if not
if strNoteID == "" then
  Nc_GUI_InfoBox("ERROR: A note must be selected before executing this action. Execution was terminated.", 1, "ERROR")
  return
end

-- execute function to get selection as HTML 
local s, nSelFrom, nSelTo = Get_Selected_Note_Content(nDocID, strNoteID, 1)

-- execute function to detect list markup in string
local nDetected = Test_String_For_Substrings(s)
if nDetected ~= 1 then 
  Nc_GUI_InfoBox("ERROR: List markup detected. Selection must not include bullet list markup. Execution terminated.", 1, "ERROR")
  return -- abort script
end

-- execute function to join lines
s = JoinStringLines(s)

-- execute function, replacing selected text with reformatted HTML and repositioning the cursor
Replace_Selected_Note_Content(nDocID, strNoteID, s, 1, nSelFrom, nSelTo)

