/margrave/helpers.rkt

http://github.com/tnelson/Margrave · Racket · 165 lines · 107 code · 34 blank · 24 comment · 28 complexity · 4ab33fb5a6f047bb73cdfe61ad9883df MD5 · raw file

  1. #lang racket
  2. (require srfi/13
  3. syntax/readerr)
  4. (provide (all-defined-out))
  5. ;****************************************************************
  6. ; HELPERS
  7. ; using a mutable hash table for now. if switch to immutable, can fold table creation over the-list
  8. (define (partition* bucket-func the-list #:init-keys [init-keys '()])
  9. (define result-hash (make-hash))
  10. ; initialize
  11. (for-each (lambda (k) (hash-set! result-hash k empty)) init-keys)
  12. (for-each (lambda (x)
  13. (define bucket (bucket-func x))
  14. (when bucket
  15. (if (hash-has-key? result-hash bucket)
  16. (hash-set! result-hash bucket (cons x (hash-ref result-hash bucket)))
  17. (hash-set! result-hash bucket (list x)))) )
  18. the-list)
  19. result-hash)
  20. ; (partition* (lambda (x) (and (even? x) (remainder x 3))) '(1 2 3 4 5 6 7 8 9 10))
  21. ; '#hash((0 . (6)) (2 . (8 2)) (1 . (10 4)))
  22. (define (fold-append-with-spaces posslist)
  23. (fold-append-with-separator posslist " "))
  24. ; May be a list, may not be a list
  25. (define (fold-append-with-separator posslist separator)
  26. (if (list? posslist)
  27. (foldr (lambda (s t)
  28. (let ([s-str (if (symbol? s)
  29. (symbol->string s)
  30. s)]
  31. [t-str (if (symbol? t)
  32. (symbol->string t)
  33. t)])
  34. (cond
  35. [(string=? s-str "") t-str]
  36. [(string=? t-str "") s-str]
  37. [else (string-append s-str separator t-str)])))
  38. ""
  39. posslist)
  40. (if (symbol? posslist)
  41. (symbol->string posslist)
  42. posslist)))
  43. (define (fold-append-with-spaces-quotes posslist)
  44. (fold-append-with-spaces (if (list? posslist)
  45. (map symbol->quoted-string posslist)
  46. posslist)))
  47. ; symbol or string -> string
  48. ; Returns the argument, quoted, as a string.
  49. (define (symbol->quoted-string arg)
  50. (if (symbol? arg)
  51. (string-append "\"" (symbol->string arg)"\"")
  52. (string-append "\"" arg "\"")))
  53. (define (symbol->string/safe arg)
  54. (if (symbol? arg)
  55. (symbol->string arg)
  56. arg))
  57. (define (wrap-list-parens lst)
  58. (fold-append-with-spaces (map (lambda (str) (string-append "(" str ")")) lst)))
  59. (define (safe-get-margrave-collection-path)
  60. (with-handlers ([(lambda (e) (exn:fail:filesystem? e))
  61. (lambda (e) #f)])
  62. (collection-path "margrave")))
  63. (define (resolve-margrave-filename-keyword raw-filename)
  64. (define the-filename (cond [(path? raw-filename)
  65. (path->string raw-filename)]
  66. [(symbol? raw-filename)
  67. (symbol->string raw-filename)]
  68. [else
  69. raw-filename]))
  70. (define loc (string-contains-ci the-filename "*MARGRAVE*"))
  71. (define coll-path-string (path->string (safe-get-margrave-collection-path)))
  72. (define result (cond [(or (not loc) (> loc 1))
  73. the-filename]
  74. [(equal? loc 1)
  75. (string-replace the-filename coll-path-string 0 11)]
  76. [else
  77. (string-replace the-filename coll-path-string 0 10)]))
  78. ; Avoid confusion: prevent mixed use of / and \ in the same path.
  79. (path->string (simplify-path result)))
  80. ; file-exists?/error
  81. ; filename src-syntax -> boolean
  82. ; If file does not exist, raises an error
  83. (define (file-exists?/error file-path src-syntax [error-message (format "File did not exist: ~a~n" file-path)])
  84. (cond [(and file-path (file-exists? file-path))
  85. #t]
  86. [(syntax? src-syntax)
  87. (raise-read-error
  88. error-message
  89. (syntax-source src-syntax)
  90. (syntax-line src-syntax)
  91. (syntax-column src-syntax)
  92. (syntax-position src-syntax)
  93. (syntax-span src-syntax))]
  94. [else (raise-user-error error-message)]))
  95. ; filename syntax -> port
  96. ; If file does not exist, raises an exception. If syntax has been passed, will enable syntax highlighting.
  97. (define (open-input-file/exists file-name src-syntax [error-message (format "File did not exist: ~a~n" file-name)])
  98. (define file-path (build-path file-name))
  99. (define actual-file-name (path->string (file-name-from-path file-path)))
  100. (define actual-path (path-only/same file-path))
  101. (define safe-path (build-path/file-ci actual-path actual-file-name))
  102. (and (file-exists?/error safe-path src-syntax error-message)
  103. (open-input-file safe-path)))
  104. (define (path-only/same the-path)
  105. (define p (path-only the-path))
  106. (if p
  107. p
  108. (build-path 'same)))
  109. ;;;;;;;;;;;;;;;;;;;;;;;;
  110. ; Deal with the fact that the .p file contains a vocab name,
  111. ; and the name's capitalization may not match the file's.
  112. ; Returns #f if no such file exists.
  113. ; Does not accept 'same or 'up
  114. (define/contract (build-path/file-ci location want-filename)
  115. [path? string? . -> . (or/c path? #f)]
  116. ;(printf "buildpath/file-ci: loc: ~v want-filename: ~v curr-dir: ~v~n" location want-filename (current-directory))
  117. (define (my-filter fullpath)
  118. (define fname (file-name-from-path fullpath))
  119. (and fname (string-ci=? want-filename (path->string fname))))
  120. ; Don't use find-files, because that recurses and we want to be local.
  121. ; (It also has problems if one of the dirs it is recurring on lacks permissions...)
  122. (define folder-contents-fullpaths (map (lambda (fpath) (build-path location fpath))
  123. (directory-list location)))
  124. (define files-in-folder (filter file-exists? folder-contents-fullpaths))
  125. ;(printf "Testing vs. files: ~v~n" files-in-folder)
  126. (define files-found (filter my-filter files-in-folder))
  127. (cond [(< (length files-found) 1) #f]
  128. [(> (length files-found) 1) (raise-user-error (format "Ambiguous case-insensitive file name. Asked for ~v in ~v, but there were multiple matches: ~v"
  129. want-filename (path->string location)
  130. (map path->string files-found)))]
  131. [else (first files-found)]))