(defparameter *width* 120) (defun date (start end) (format nil "~A/~A" start end)) (defun gpa (gpa bounds) (format nil "~A/~A" gpa bounds)) (defun education (&key school location start end degree majorgpa totalgpa) (let ((locationtext (format nil "~A: ~A - ~A" location start end)) (majortext (format nil "~A Major GPA" majorgpa)) (totaltext (format nil "~A Total GPA" totalgpa))) (format nil "Education~%~V,,,'-A~%~A~V@A~%~V@A~%~V@A~%~V@A~%" (* 2 (/ *width* 3)) "-" school (- *width* (length school)) locationtext (- *width* (- (length locationtext) (length degree))) degree (- *width* (- (length locationtext) (length majortext))) majortext (- *width* (- (length locationtext) (length totaltext))) totaltext))) (defun skills (skill-list) (format nil "Relevant Skills~%~V,,,'-A~%~{~{~A~V@A~}~%~}" (* 2 (/ *width* 3)) "-" (mapit (let ((left-text (handle-desc-element (car it) :left 0))) (list left-text (- *width* (length left-text)) (if (stringp (cadr it)) (cadr it) (format nil "~V@A~{~{~%~V@A~}~}" (- *width* (length left-text)) (caadr it) (mapit (list *width* it) (cdadr it)))))) skill-list))) (defun handle-desc-list (list left) (format nil "~{~{~,,V@A~A~}~^~%~}" (mapit (list left " * " (handle-desc-element it :left (+ 4 left) :ignore-left t)) list))) (defun handle-paragraph-element (p-elem) (cond ((stringp p-elem) p-elem) ((and (listp p-elem) (eql (car p-elem) 'bold)) (format nil "_~A_" (cadr p-elem))) ((and (listp p-elem) (eql (car p-elem) 'invisible)) (format nil "~VA" (length (cadr p-elem)) " ")))) (defun handle-paragraph (paragraph left &key ignore-left) (breakup-string (format nil "~{~A~}" (mapcar #'handle-paragraph-element paragraph)) left :ignore-left ignore-left)) (defun handle-desc-element (desc-element &key (left 4) ignore-left) (cond ((stringp desc-element) (breakup-string desc-element left :ignore-left ignore-left)) ((and (listp desc-element) (eql 'list (car desc-element))) (handle-desc-list (cdr desc-element) left)) ((listp desc-element) (handle-paragraph desc-element left :ignore-left ignore-left)) )) (defun breakup-string (string left &key ignore-left) (if (< (length string) (- *width* left)) (format nil "~,,V@A" (if ignore-left 0 left) string) (let ((break-space-pos (position #\Space string :from-end t :end (- *width* left)))) (format nil "~,,V@A~%~A" (if ignore-left 0 left) (subseq string 0 break-space-pos) (breakup-string (subseq string (1+ break-space-pos)) left))))) (defun print-description (description) (format nil "~{~A~%~}" (mapcar #'handle-desc-element description)) ) (defun pos (&key position start end description one-line) (format nil " ~A (~A - ~A)~%~A" position start (or end "Present") (print-description description))) (defun all-work (work) (format nil "Work Experience~%~V,,,'-A~%~{~A~%~}" (* 2 (/ *width* 3)) "-" work)) (defun work (&key company positions) (format nil "~A~%~{~A~^~%~}" company positions)) (defun all-oss (oss-projs) (format nil "Open Source Projects~%~V,,,'-A~%~{~A~}" (* 2 (/ *width* 3)) "-" oss-projs)) (defun oss-proj (&key project project-desc project-website role start end) (format nil "~A (~A)~% ~A (~A - ~A)~%~A" project project-website role start (or end "Present") (print-description project-desc))) (defun resume (&key name email phone addr1 addr2 education skills work oss) (format nil "~:@(~V@A~)~%~A~V@A~%~A~V@A~%~%~A~%~A~%~A~A" (+ (/ *width* 2) (/ (length name) 2)) name email (- *width* (length email)) addr1 phone (- *width* (length phone)) addr2 education skills (all-work work) (all-oss oss))) (defun dump-to-text (resume-file out-file) (with-open-file (out out-file :direction :output :if-exists :supersede) (with-open-file (in resume-file) (format out "~A" (eval (read in))))))