1"
2" cream-dailyread.vim -- Select a daily reading from master document.
3"
4" Cream -- An easy-to-use configuration of the famous Vim text editor
5" [ http://cream.sourceforge.net ] Copyright (C) 2001-2011 Steve Hall
6"
7" License:
8" This program is free software; you can redistribute it and/or modify
9" it under the terms of the GNU General Public License as published by
10" the Free Software Foundation; either version 3 of the License, or
11" (at your option) any later version.
12" [ http://www.gnu.org/licenses/gpl.html ]
13"
14" This program is distributed in the hope that it will be useful, but
15" WITHOUT ANY WARRANTY; without even the implied warranty of
16" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17" General Public License for more details.
18"
19" You should have received a copy of the GNU General Public License
20" along with this program; if not, write to the Free Software
21" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22" 02111-1307, USA.
23"
24" Description:
25" * open a given document
26" * chop out the section equivalent to the portion and position for
27"   that day of the year plus a day on either side. (Optional, prompt
28"   or pass argument for which day's portion to get.)
29" * paste into a temporary document for daily reading
30" * demarcate today's read from context
31
32" register as a Cream add-on
33if exists("$CREAM")
34	call Cream_addon_register(
35	\ "Daily Read",
36	\ "Read a days portion of a document",
37	\ "Choose a document to read in entirety over a year and select and present that day's portion, including a day's context on either side. Great for meditative or religious readings.",
38	\ "Daily Read",
39	\ "call Cream_dailyread()",
40	\ '<Nil>'
41	\ )
42endif
43
44function! Cream_dailyread(...)
45
46	" determine what we're reading
47	" if unset
48	if !exists("g:CREAM_DAILYREAD")
49		call confirm("Select a file from which to read daily portions...", "&Continue...", 1, "Info")
50		let myreturn = s:Cream_dailyread_setfile()
51		if myreturn != 1
52			call confirm("Valid file not found. Quitting...", "&Ok", 1, "Error")
53			return
54		endif
55	endif
56	" if unreadable
57	if !filereadable(g:CREAM_DAILYREAD)
58		call confirm("Unable to read previously selected daily read document. Select a new file...", "&Continue...", 1, "Info")
59		let myreturn = s:Cream_dailyread_setfile()
60		if myreturn != 1
61			call confirm("Valid file not found. Quitting...", "&Ok", 1, "Error")
62			return
63		endif
64	endif
65
66	" dialog
67	let n = confirm(
68		\ "Select option...\n" .
69		\ "\n", "&Select\ Day\n&Select\ New\ Document\n&Ok\n&Cancel", 3, "Info")
70	let myday = ""
71	while myday == ""
72		if     n == 1
73			" get optional day to display
74			" manual call uses argument for day
75			if exists("a:1")
76				let myday = a:1
77			endif
78			" otherwise, prompt for day
79			if myday == ""
80				let myday = inputdialog("Please enter desired day number for reading.\n(Default is today, below.)", strftime("%j"))
81				" if empty, user is trying to quit
82				if myday == ""
83					call confirm(
84						\ "No day entered. Quitting...\n" .
85						\ "\n", "&Ok", 1, "Info")
86					return
87				endif
88			endif
89		elseif n == 2
90			let n = s:Cream_dailyread_setfile()
91			if n != 1
92				" didn't find a valid file
93				return
94			endif
95		elseif n == 3
96			" continue, use current day
97			let myday = strftime("%j")
98		else
99			" abort
100			return
101		endif
102	endwhile
103
104	" remove leading 0s on myday (known strftime() error on Win95)
105	while myday[0] == 0
106		let myday = strpart(myday, 1)
107	endwhile
108
109	" turn off myautoindent
110	let myautoindent = &autoindent
111	set noautoindent
112
113	" escape spaces and backslashes
114	let myfile = escape(g:CREAM_DAILYREAD, ' \')
115
116	" open master
117	execute "silent! view " . myfile
118
119	" calculate how long 1/(days in year) is by bytes (don't use
120	" getfsize()--will cause error with compressed files)
121	let mydoclen = line2byte("$")
122	" number of days in the year
123	let days = Cream_daysinyear()
124	let mydaylen = mydoclen / days
125	" must be at least one
126	if mydaylen < 1
127		let mydaylen = 1
128	endif
129
130	" validate day number (must happen after days calculated)
131	if myday > days || myday < 1
132		call confirm("Invalid day number provided. Defaulting to today...", "&Ok", 1, "Info")
133		unlet myday
134	endif
135
136	" find day of year number (if options above don't already provide)
137	if !exists("myday")
138		" numerical day of the year
139		let myday = strftime("%j") - 1
140	endif
141	" calculate current date's pos in year
142	" position = day count * length/day
143	let mypos = myday * mydaylen - mydaylen - mydaylen
144	if mypos < 0
145		let mypos = 1
146	endif
147
148	" go to byte count equivalent to day's start position
149	silent! execute "normal :goto " . mypos . "\<CR>"
150	if myday != 1
151		" select 3/364th of document down
152		silent! execute "normal v" . (mypos + (mydaylen * 3)) . "go"
153	else
154		" select 2/364th of document down
155		silent! execute "normal v" . (mypos + (mydaylen * 2)) . "go"
156	endif
157
158	" copy (register "x")
159	silent! normal "xy
160	" close master (don't save)
161	silent! bwipeout!
162	" open new document named with today's day number
163	silent! execute "silent! edit! " . myday
164	" paste (register "x")
165	silent! normal "xp
166
167	" mark today from context
168	" quit visual mode
169	if mode() == "v"
170		normal v
171	endif
172	normal i
173	" go to start of read
174	if myday != 1
175		silent! execute "normal :goto " . mydaylen . "\<CR>"
176	else
177		silent! execute "normal :goto " . 1 . "\<CR>"
178	endif
179	" start of line
180	normal g0
181	" insert line
182	silent! execute "silent! normal i\n\n======================================================================\n"
183	silent! execute "silent! normal i\t(Today's read below)\n\n"
184	" go to end of read
185	if myday != 1
186		silent! execute "normal :goto " . ((mydaylen * 2) + 5) . "\<CR>"
187	else
188		silent! execute "normal :goto " . ((mydaylen * 1) + 5) . "\<CR>"
189	endif
190	" start of line
191	normal g0
192	" insert line
193	silent! execute "silent! normal i\n\n\t(Today's read above)\n"
194	silent! execute "silent! normal i======================================================================\n\n"
195	" go back to beginning of today's read
196	if myday != 1
197		silent! execute "normal :goto " . (mydaylen + 4) . "\<CR>"
198	else
199		silent! execute "normal :goto " . (    1    + 4) . "\<CR>"
200	endif
201
202	" return autoinsert state
203	let &autoindent = myautoindent
204
205	" don't warn the user about unsaved state
206	set nomodified
207
208endfunction
209
210function! s:Cream_dailyread_setfile()
211" file open dialog to select file
212" establish global for daily read file
213" return -1 if file not found or unreadable
214
215	if exists("g:CREAM_DAILYREAD")
216		" default path (current)
217		let tmp1 = fnamemodify(g:CREAM_DAILYREAD, ":p:h")
218		let tmp1 = escape(tmp1, ' ')
219		" default filename (current)
220		let tmp2 = fnamemodify(g:CREAM_DAILYREAD, ":p")
221		let tmp2 = escape(tmp2, ' ')
222		" reverse backslashes
223		if has("win32")
224			let tmp1 = substitute(tmp1, '/', '\\', 'g')
225			let tmp2 = substitute(tmp2, '/', '\\', 'g')
226		endif
227		let myfile = browse('1', 'Select Daily Read file...', tmp1, tmp2)
228	else
229		let myfile = browse("1", "Select Daily Read file...", getcwd(), "")
230	endif
231
232	" at least on unix, requires a full path
233	let myfile = fnamemodify(myfile, ":p")
234
235	" results
236	if filereadable(myfile) != 1
237		return -1
238	else
239		let g:CREAM_DAILYREAD = myfile
240		return 1
241	endif
242
243endfunction
244
245