You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.3 KiB

  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package util contains utility types and functions for godoc.
  5. package util // import "golang.org/x/tools/godoc/util"
  6. import (
  7. pathpkg "path"
  8. "sync"
  9. "time"
  10. "unicode/utf8"
  11. "golang.org/x/tools/godoc/vfs"
  12. )
  13. // An RWValue wraps a value and permits mutually exclusive
  14. // access to it and records the time the value was last set.
  15. type RWValue struct {
  16. mutex sync.RWMutex
  17. value interface{}
  18. timestamp time.Time // time of last set()
  19. }
  20. func (v *RWValue) Set(value interface{}) {
  21. v.mutex.Lock()
  22. v.value = value
  23. v.timestamp = time.Now()
  24. v.mutex.Unlock()
  25. }
  26. func (v *RWValue) Get() (interface{}, time.Time) {
  27. v.mutex.RLock()
  28. defer v.mutex.RUnlock()
  29. return v.value, v.timestamp
  30. }
  31. // IsText reports whether a significant prefix of s looks like correct UTF-8;
  32. // that is, if it is likely that s is human-readable text.
  33. func IsText(s []byte) bool {
  34. const max = 1024 // at least utf8.UTFMax
  35. if len(s) > max {
  36. s = s[0:max]
  37. }
  38. for i, c := range string(s) {
  39. if i+utf8.UTFMax > len(s) {
  40. // last char may be incomplete - ignore
  41. break
  42. }
  43. if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' {
  44. // decoding error or control character - not a text file
  45. return false
  46. }
  47. }
  48. return true
  49. }
  50. // textExt[x] is true if the extension x indicates a text file, and false otherwise.
  51. var textExt = map[string]bool{
  52. ".css": false, // must be served raw
  53. ".js": false, // must be served raw
  54. }
  55. // IsTextFile reports whether the file has a known extension indicating
  56. // a text file, or if a significant chunk of the specified file looks like
  57. // correct UTF-8; that is, if it is likely that the file contains human-
  58. // readable text.
  59. func IsTextFile(fs vfs.Opener, filename string) bool {
  60. // if the extension is known, use it for decision making
  61. if isText, found := textExt[pathpkg.Ext(filename)]; found {
  62. return isText
  63. }
  64. // the extension is not known; read an initial chunk
  65. // of the file and check if it looks like text
  66. f, err := fs.Open(filename)
  67. if err != nil {
  68. return false
  69. }
  70. defer f.Close()
  71. var buf [1024]byte
  72. n, err := f.Read(buf[0:])
  73. if err != nil {
  74. return false
  75. }
  76. return IsText(buf[0:n])
  77. }