AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Custom text wrapping script

 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Gehn



Joined: 02 Mar 2005
Posts: 13
Location: Terminus of Tears

PostPosted: Wed Mar 02, 2005 11:47 pm    Post subject: Custom text wrapping script Reply with quote

While working on creating a GUI for a bigger project, I found that neither text nor edit elements really wrapped like how I wanted them to for the situation. Then, I got the idea to design a wrapping system of my own, that manually put in newline statements. The prototype was successful, so I made this - a better designed and more feature complete version. Its header explains its usage.

Text Wrapper.ahk
Code:

; AutoHotkey Version: 1.0.29
; Language:       English
; Platform:       Windows XP
; Author:         Gehn WillowGlade <gehnofsol@bigfoot.com>
;
; Script Function:
;   Wraps text manually by adding in newline statements to a string using
;   a configurable methodology. Configuration is done by setting specific
;   variables, detailed below. Settings are remembered between calls. Most
;   variables have a default and hence do not absolutely require setting.
;   Text is wrapped by breaking the lines as long as possible, at certain
;   'break characters' defined in sets. These sets have priority, starting
;   at 1. Wrap Text will attempt to break the line using set 1, and if it
;   fails, it will continue on to set 2, and so forth, until it runs out of
;   sets. The result is that it will prefer wrapping very short lines to
;   wrapping at lower priority break characters.
;
; Variables:
;   textToWrap                - The text to be wrapped. No default.
;   maxCharactersPerLine      - The number of characters that are allowed
;                               on a line before a wrap is attempted. This
;                               setting defaults to 80.
;   breakType                 - This can be set to either 'after', 'before'
;                               or 'eat'. 'after' will have lines break after
;                               the break character. 'before' will have the
;                               lines break before the break character. 'eat'
;                               will destroy the break character entirely.
;                               This setting defaults to 'after'.
;   breakCharacterSet[*]      - A set of individual characters which all
;                               have the same priority, starting at 1. Do
;                               not include spaces unless you want space to
;                               be a break character. Use a blank set to end
;                               the set list.
;   breakCharacterSet[*]_type - This allows the break type to be set on a per
;                               break character set basis. This setting
;                               defaults to the breakType setting.
;   forceWrap                 - This will force wrapping of the text, even if
;                               no break characters are found. In such a case
;                               the line will break right at the limit. Set
;                               this option using true or false. The default
;                               is false.
;   wrappedText               - This variable is not set. Instead, this is the
;                               text, wrapped, returned by Wrap Text.
;
; Example:
;   textToWrap := "C:\Games\Guild Wars\GW.exe"
;   maxCharactersPerLine := 10
;   breakCharacterSet[1] := "\"
;   breakCharacterSet[2] := " "
;   breakCharacterSet[3] := ""
;   Gosub , WrapText
;
;   wrappedText would be: "C:\Games\`nGuild`nWars\`nGW.exe"


; Invoked externally to perform core function
WrapText:
  {
  Gosub , WrapText_Initialize
  If ErrorLevel <> 0
    Return

  Gosub , WrapText_BreakIntoLines

  Gosub , WrapText_CombineLines

  Return
  }

; Makes sure all variables are user set or filled with defaults (where applicable)
WrapText_Initialize:
  {
  If ( textToWrap = "" )
    {
    MsgBox , 48 , WrapText Error , The variable 'textToWrap' must be set when WrapText is called.
    ErrorLevel := 1
    Return
    }

  If ( maxCharactersPerLine = "" )
    {
    maxCharactersPerLine := 80
    }
  Else If maxCharactersPerLine is not integer
    {
    MsgBox , 48 , WrapText Error , The variable 'maxCharactersPerLine' must be a positive, nonzero integer.
    ErrorLevel := 1
    Return
    }
  Else If ( maxCharactersPerLine <= 0 )
    {
    MsgBox , 48 , WrapText Error , The variable 'maxCharactersPerLine' must be a positive, nonzero integer.
    ErrorLevel := 1
    Return
    }

  If ( breakType = "" )
    {
    breakType := "after"
    }
  Else If ( !( breakType = "after" OR breakType = "before" OR breakType = "eat" ) )
    {
    MsgBox , 48 , WrapText Error , The variable 'breakType' may only be set to 'after', 'before' or 'eat'.
    ErrorLevel := 1
    Return
    }

  If ( breakCharacterSet[1] = "" )
    {
    breakCharacterSet[1] := " "
    }

  Loop
    {
    If ( breakCharacterSet[%a_index%] == "" )
      Break

    If ( !( breakCharacterSet[%a_index%]_breakType = "" OR breakCharacterSet[%a_index%]_breakType = "after" OR breakCharacterSet[%a_index%]_breakType = "before" OR breakCharacterSet[%a_index%]_breakType = "eat" ) )
      {
      MsgBox , 48 , WrapText Error , The variable 'breakCharacterSet[%a_index%]_breakType' may only be set to 'after', 'before' or 'eat'.
      ErrorLevel := 1
      Return
      }
    }

  If ( forceWrap = "" )
    {
    forceWrap := false
    }
  Else If ( !( forceWrap = true OR forceWrap = false ) )
    {
    MsgBox , 48 , WrapText Error , The variable 'forceWrap' must be either true or false.
    ErrorLevel := 1
    Return
    }

  Return
  }

; Breaks the text into lines, as needed
WrapText_BreakIntoLines:
  {
  ; Chop off the ends of lines, to create new lines, until all lines are under the character limit

  WrapText_line[1] := textToWrap
  WrapText_lineCount := 1
  Loop
    {
    WrapText_currentLineNumber := a_index

    StringLen , WrapText_currentLineLength , WrapText_line[%WrapText_currentLineNumber%]
    If ( WrapText_currentLineLength <= maxCharactersPerLine )
      Break
    Else
      {
      ; Loop through break character sets until a break character is found, or we run out of sets

      WrapText_breakCharacterPosition := -1
      Loop
        {
        ; Search backwards from farthest possible character to find a break character

        WrapText_currentBreakCharacterSet := a_index

        If ( ( WrapText_breakCharacterPosition >= 0 ) OR ( ( breakCharacterSet[%WrapText_currentBreakCharacterSet%] = "" ) AND !forceWrap ) )
          Break

        If ( ( breakCharacterSet[%WrapText_currentBreakCharacterSet%] = "" ) AND forceWrap )
          WrapText_forceWrapThisLine := true
        Else
          WrapText_forceWrapThisLine := false

        If ( breakCharacterSet[%WrapText_currentBreakCharacterSet%]_breakType != "" )
          WrapText_currentBreakType := breakCharacterSet[%WrapText_currentBreakCharacterSet%]_breakType
        Else
          WrapText_currentBreakType := breakType

        If ( WrapText_currentBreakType = "after" )
          WrapText_currentPosition := maxCharactersPerLine
        Else
          WrapText_currentPosition := maxCharactersPerLine + 1

        Loop , %maxCharactersPerLine%
          {
          If ( WrapText_forceWrapThisLine )
            WrapText_breakCharacterPosition := 1
          Else
            {
            StringMid , WrapText_characterAtCurrentPosition , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition , 1
            StringGetPos , WrapText_breakCharacterPosition , breakCharacterSet[%WrapText_currentBreakCharacterSet%] , %WrapText_characterAtCurrentPosition%
            }

          If ( WrapText_breakCharacterPosition >= 0 )
            {
            WrapText_lineCount += 1
            If ( WrapText_currentBreakType = "after" )
              {
              StringTrimLeft , WrapText_line[%WrapText_lineCount%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition
              StringLeft , WrapText_line[%WrapText_currentLineNumber%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition
              }
            Else If ( WrapText_currentBreakType = "before" )
              {
              StringTrimLeft , WrapText_line[%WrapText_lineCount%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition - 1
              StringLeft , WrapText_line[%WrapText_currentLineNumber%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition - 1
              }
            Else ; WrapText_currentBreakType = "eat"
              {
              StringTrimLeft , WrapText_line[%WrapText_lineCount%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition
              StringLeft , WrapText_line[%WrapText_currentLineNumber%] , WrapText_line[%WrapText_currentLineNumber%] , WrapText_currentPosition - 1
              }

            Break
            }

          WrapText_currentPosition -= 1
          }
        }
      }
    }

  Return
  }

; Recombines the text into a single variable
WrapText_CombineLines:
  {
  wrappedText := ""
  Loop , %WrapText_lineCount%
    {
    WrapText_currentLine := WrapText_line[%a_index%]
    wrappedText := wrappedText "`n" WrapText_currentLine
    }
  StringTrimLeft , wrappedText , wrappedText , 1

  Return
  }


I'm mostly happy with the result. It seems fully functional - if anybody spots a bug please let me know. Any other comments would be nice too - this is the first time I've actually put out any code for public display and I imagine I could use some feedback.

However, there's three layers of looping in the WrapText_BreakIntoLines function however, and combined with the ifs in said section, there's a bit more nesting than I'd like. It makes the code less clear than it could be. I considered, and am still considering, moving some of the code from WrapText_BreakIntoLines into other functions. That could make the function much clearer in some ways, but then you'd have even more variables crossing functions and more function call overhead. Thoughts on this issue would be appreciated.

Edit: I apologize that some of the lines are really long, it makes the formatting here (and in any text editor you may paste it into) rather ugly.
_________________
The dumber people think you are, the more surprised they're going to be when you kill them.
Back to top
View user's profile Send private message Send e-mail AIM Address
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Thu Mar 03, 2005 12:06 am    Post subject: Reply with quote

Your sig is awesome. Wink

A witty sig and a few good scripts will get you anything in this forum. Cool
Back to top
View user's profile Send private message
Gehn



Joined: 02 Mar 2005
Posts: 13
Location: Terminus of Tears

PostPosted: Thu Mar 03, 2005 2:55 am    Post subject: Reply with quote

Unfortunately, I can't take credit for my signature. It's a quote from William Clayton.
_________________
The dumber people think you are, the more surprised they're going to be when you kill them.
Back to top
View user's profile Send private message Send e-mail AIM Address
observer_420
Guest





PostPosted: Sun Mar 06, 2005 5:05 pm    Post subject: filtering text through arbitrary unix (cygwin) filters Reply with quote

Heh... if you have Cygwin installed (and what a wonderful way to get Unix commands in your Windows box!), you can use the fmt(1) command to wrap your text in default and optional ways.


Code:

;
; AutoHotkey Version: 1.x
; Language:       English
; Platform:       Win9x/NT
; Author:         Doug Snead
;
; Script Function:
;   filter text through arbitrary unix (cygwin)
;   stdin/stdout filters (in perl)
;
menu tray, tip, HotKey: windows t`r`nfilter selected text

TMPDIR = C:\cygwin\tmp               ; = /tmp in cygwin installation
TMPFILEIN = %TMPDIR%\filtr_in.tmp    ; = /tmp/filtr_in.tmp, _out.tmp
TMPFILEOUT = %TMPDIR%\filtr_out.tmp
BINDIR = C:\cygwin\bin               ; of sh(1) executable
Command = fmt                        ; default filter command

;;
;;  run selected text through a Unix filter (stdin/stdout) command
;;
#t::  ;; = the Windows key and the t key together
    saveClipBoard = %clipboard%
    Send, ^c   ;; copy selected text into clipboard
    FileAppend, %clipboard%, %TMPFILEIN%
    InputBox, Command, select stdio filter, unix filter command:,,350,150,,,,,%Command%
    if ErrorLevel = 0
    {
            TrayTip, running:, %Command%, 120, 16
       RunWait, %BINDIR%\sh.exe -c "dos2unix </tmp/filtr_in.tmp | %Command% | unix2dos >/tmp/filtr_out.tmp",,Hide
       TrayTip
       FileRead, clipboard, %TMPFILEOUT%
       Send, ^v  ;; paste processed text back in
       FileDelete, %TMPFILEOUT%
    }
    clipboard = %saveClipBoard%
    saveClipBoard =
    FileDelete, %TMPFILEIN%
    return



That script should work from any windows application that allows Ctl v copy and Ctl v paste operations.

Use the unix tidy command to reformat html, etc.
Back to top
fsnow55



Joined: 08 Jun 2006
Posts: 19

PostPosted: Tue Jun 20, 2006 4:15 pm    Post subject: Reply with quote

Hopefully, the last person to post the cygwin filter script will reply, or somebody that knows will reply:

This script looks like it matches my need but
I did not get any useful output from this script. Perhaps the problem is with the quotes here?

RunWait, %BINDIR%\sh.exe -c "dos2unix </tmp/filtr_in.tmp | %Command% | unix2dos > /tmp/filtr_out.tmp",,Hide



I tried different combinations of quoting but can not get output to /tmp/filtr_out.tmp (it never got created).
I think the problem is with the %Command% variable in the string.

BTW, this works:
RunWait, %BINDIR%\sh.exe -c "echo haha > /tmp/haha.txt"

Appreciate your help.
Back to top
View user's profile Send private message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Tue Jun 20, 2006 5:06 pm    Post subject: Reply with quote

Maybe using 2 quoteded sections would work (so the variable isn't enclosed):
Code:
"dos2unix </tmp/filtr_in.tmp | " %Command% " | unix2dos > /tmp/filtr_out.tmp",,
Back to top
View user's profile Send private message
fsnow55



Joined: 08 Jun 2006
Posts: 19

PostPosted: Tue Jun 20, 2006 7:07 pm    Post subject: Reply with quote

Thanks. I found out the problem isn't with the quotes but that I have to fully qualify all the cygwin commands e.g. this works:

RunWait, %BINDIR%\sh.exe -c "/usr/bin/dos2unix </tmp/filtr_in.tmp | %Command% | /usr/bin/unix2dos > /tmp/filtr_out.tmp",,Hide


and in the popup, I type the full path for the command e.g. /usr/bin/fmt -w 20

I'm new to cygwin, so need to find out how to "auto-source" the path so XP/AHK can understand it.
Back to top
View user's profile Send private message
fsnow55



Joined: 08 Jun 2006
Posts: 19

PostPosted: Tue Jun 20, 2006 8:00 pm    Post subject: Reply with quote

Finally solved it with help from:
http://www.astro.umd.edu/~harris/cygwin/

i.e. need to set the C:/Cygwin/bin path in my windows path.
Back to top
View user's profile Send private message
Kudos



Joined: 21 Aug 2006
Posts: 20

PostPosted: Sat Oct 07, 2006 3:45 pm    Post subject: thanks Reply with quote

Gehn, thanks for this - it was very helpful to me! Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group