yard 0.9.36 → 0.9.37

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1f492861606b6ce24d390317f2a97ccbd67bbf73b8b964ea6f9e61bb4096d9e
4
- data.tar.gz: 1a4ec96bd604c8ab68cf6c971fc22aff400f2d8ed853d3b0b5fc222f4c8e7767
3
+ metadata.gz: 0774d1772b133075737690acbc502767f6fef28d3765a14929074259248f3981
4
+ data.tar.gz: '068103b3caf24a6c6071a6c9b0f52bd58641fd0c03e22220fb2d1b09a104385c'
5
5
  SHA512:
6
- metadata.gz: 04b727cb198fd9559a9314989fae7bcf60202531f5ab634d211780b5bbf15b60341d8a8f5fa6fd890c743c7d1b953e7b49d3c8e73997f3397b7344a70442fd29
7
- data.tar.gz: c3df5e59c450adfc6d6088bd7c6a6c64f4477c1de65eae7cbd21e1c4ca410d606179bc88c84ed084b22d7b3f8bf66cc67426e9c103558b0a25c5ab01c1900ab9
6
+ metadata.gz: 64a799b2f45d7ad6aad8684c805344f242c8e2f8ef1c60a43094bc237bccd449ee1c93c60c0f54a36f05a79e5b652636d7170dce85941b1f74a4bcc173c92c21
7
+ data.tar.gz: b19ba690f1a244b0c7df5c1524f77355323fa9164e9496c609f258b3d0691c0a3d807cd985f20f335884ba1d8e97193149d4a7b9e1eebd9ed3a43431492a1ce3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # main
2
2
 
3
+ # [0.9.37] - September 4th, 2024
4
+
5
+ [0.9.37]: https://github.com/lsegal/yard/compare/v0.9.36...v0.9.37
6
+
7
+ - Fix JavaScript errors in `--one-file` template (#1426)
8
+ - Fix heredoc parsing and add support for squiggly heredocs (#1315, #1495)
9
+ - Accessibility improvements to the default template (#1501)
10
+ - Improved YARD documentation (#1410, #1512, #1516, #1544)
11
+ - Fix error when parsing `@option` tags (#1515)
12
+ - Fix issue parsing UTF-8 filenames (#1517)
13
+ - Replace OpenStruct with optimized YARD::OpenStruct to avoid ostruct performance warnings (#1545)
14
+ - Add support for `private attr_*` syntax (#1541)
15
+ - Remove logger dependency (#1546)
16
+
3
17
  # [0.9.36] - February 29th, 2024
4
18
 
5
19
  [0.9.36]: https://github.com/lsegal/yard/compare/v0.9.35...v0.9.36
data/README.md CHANGED
@@ -122,6 +122,13 @@ HTML. If running `which rdoc` turns up empty, install RDoc by issuing:
122
122
  $ sudo apt-get install rdoc
123
123
  ```
124
124
 
125
+ ### Markdown parser
126
+
127
+ When rendering markdown, yard will use one of several possible markdown providers,
128
+ [in order of priority](https://github.com/lsegal/yard/blob/e833aac7a01510245dd4ae1d1d18b046c8293c2d/lib/yard/templates/helpers/markup_helper.rb#L26-L33).
129
+ If you are experiencing rendering bugs (example [1](https://github.com/lsegal/yard/issues/1410) [2](https://github.com/lsegal/yard/issues/1543)), try adding one of the
130
+ gems further up in the list to your Gemfile.
131
+
125
132
  ## Usage
126
133
 
127
134
  There are a couple of ways to use YARD. The first is via command-line, and the
@@ -185,7 +192,7 @@ Note that the README file can be specified with its own `--readme` switch.
185
192
  You can also add a `.yardopts` file to your project directory which lists the
186
193
  switches separated by whitespace (newlines or space) to pass to yardoc whenever
187
194
  it is run. A full overview of the `.yardopts` file can be found in
188
- {YARD::CLI::Yardoc}.
195
+ [YARD::CLI::Yardoc](https://rubydoc.info/gems/yard/YARD/CLI/Yardoc#label-Options+File+-28.yardopts-29).
189
196
 
190
197
  ### Queries
191
198
 
data/lib/yard/autoload.rb CHANGED
@@ -298,6 +298,7 @@ module YARD
298
298
  autoload :DocstringParser, __p('docstring_parser')
299
299
  autoload :GemIndex, __p('gem_index')
300
300
  autoload :Logger, __p('logging')
301
+ autoload :OpenStruct, __p('open_struct')
301
302
  autoload :Options, __p('options')
302
303
  autoload :Registry, __p('registry')
303
304
  autoload :RegistryResolver, __p('registry_resolver')
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  module CodeObjects
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  # Parses text and creates a {Docstring} object to represent documentation
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  module Handlers
@@ -13,10 +13,22 @@ class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base
13
13
  case statement.type
14
14
  when :var_ref, :vcall
15
15
  self.visibility = ident.first.to_sym
16
- when :fcall, :command
16
+ when :command
17
+ if RUBY_VERSION >= '3.' && is_attribute_method?(statement.parameters.first)
18
+ parse_block(statement.parameters.first, visibility: ident.first.to_sym)
19
+ return
20
+ end
21
+ process_decorator do |method|
22
+ method.visibility = ident.first if method.respond_to? :visibility=
23
+ end
24
+ when :fcall
17
25
  process_decorator do |method|
18
26
  method.visibility = ident.first if method.respond_to? :visibility=
19
27
  end
20
28
  end
21
29
  end
30
+
31
+ def is_attribute_method?(node)
32
+ node.type == :command && node.jump(:ident).first.to_s =~ /^attr_(accessor|writer|reader)$/
33
+ end
22
34
  end
data/lib/yard/logging.rb CHANGED
@@ -1,12 +1,44 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- require 'logger'
4
3
  require 'thread'
5
4
 
6
5
  module YARD
7
6
  # Handles console logging for info, warnings and errors.
8
7
  # Uses the stdlib Logger class in Ruby for all the backend logic.
9
- class Logger < ::Logger
8
+ class Logger
9
+ # Log severity levels
10
+ module Severity
11
+ # Debugging log level
12
+ DEBUG = 0
13
+
14
+ # Information log level
15
+ INFO = 1
16
+
17
+ # Warning log level
18
+ WARN = 2
19
+
20
+ # Error log level
21
+ ERROR = 3
22
+
23
+ # Fatal log level
24
+ FATAL = 4
25
+
26
+ # Unknown log level
27
+ UNKNOWN = 5
28
+
29
+ # @private
30
+ SEVERITIES = {
31
+ DEBUG => :debug,
32
+ INFO => :info,
33
+ WARN => :warn,
34
+ ERROR => :error,
35
+ FATAL => :fatal,
36
+ UNKNOWN => :unknown
37
+ }
38
+ end
39
+
40
+ include Severity
41
+
10
42
  # The list of characters displayed beside the progress bar to indicate
11
43
  # "movement".
12
44
  # @since 0.8.2
@@ -14,25 +46,31 @@ module YARD
14
46
 
15
47
  # @return [IO] the IO object being logged to
16
48
  # @since 0.8.2
17
- def io; @logdev end
18
- def io=(pipe) @logdev = pipe end
49
+ attr_accessor :io
19
50
 
20
51
  # @return [Boolean] whether backtraces should be shown (by default
21
52
  # this is on).
22
53
  def show_backtraces; @show_backtraces || level == DEBUG end
23
54
  attr_writer :show_backtraces
24
55
 
56
+ # @return [DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN] the logging level
57
+ attr_accessor :level
58
+
59
+ # @return [Boolean] whether a warn message has been emitted. Used for status tracking.
60
+ attr_accessor :warned
61
+
25
62
  # @return [Boolean] whether progress indicators should be shown when
26
63
  # logging CLIs (by default this is off).
27
64
  def show_progress
28
65
  return false if YARD.ruby18? # threading is too ineffective for progress support
29
- return false if YARD.windows? # windows has poor ANSI support
30
66
  return false unless io.tty? # no TTY support on IO
31
67
  return false unless level > INFO # no progress in verbose/debug modes
32
68
  @show_progress
33
69
  end
34
70
  attr_writer :show_progress
35
71
 
72
+ # @!group Constructor Methods
73
+
36
74
  # The logger instance
37
75
  # @return [Logger] the logger instance
38
76
  def self.instance(pipe = STDOUT)
@@ -40,13 +78,12 @@ module YARD
40
78
  end
41
79
 
42
80
  # Creates a new logger
81
+ # @private
43
82
  def initialize(pipe, *args)
44
- super(pipe, *args)
45
83
  self.io = pipe
46
84
  self.show_backtraces = true
47
85
  self.show_progress = false
48
86
  self.level = WARN
49
- self.formatter = method(:format_log)
50
87
  self.warned = false
51
88
  @progress_indicator = 0
52
89
  @mutex = Mutex.new
@@ -54,36 +91,64 @@ module YARD
54
91
  @progress_last_update = Time.now
55
92
  end
56
93
 
57
- # Changes the debug level to DEBUG if $DEBUG is set
58
- # and writes a debugging message.
59
- def debug(*args)
60
- self.level = DEBUG if $DEBUG
61
- super
94
+ # @!macro [attach] logger.create_log_method
95
+ # @method $1(message)
96
+ # Logs a message with the $1 severity level.
97
+ # @param message [String] the message to log
98
+ # @see #log
99
+ # @return [void]
100
+ # @private
101
+ def self.create_log_method(name)
102
+ severity = Severity.const_get(name.to_s.upcase)
103
+ define_method(name) { |message| log(severity, message) }
62
104
  end
63
105
 
106
+ # @!group Logging Methods
107
+
108
+ create_log_method :info
109
+ create_log_method :error
110
+ create_log_method :fatal
111
+ create_log_method :unknown
112
+
113
+ # Changes the debug level to DEBUG if $DEBUG is set and writes a debugging message.
114
+ create_log_method :debug
115
+
64
116
  # Remembers when a warning occurs and writes a warning message.
65
- def warn(*args)
66
- self.warned = true
67
- super
117
+ create_log_method :warn
118
+
119
+ # Logs a message with a given severity
120
+ # @param severity [DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN] the severity level
121
+ # @param message [String] the message to log
122
+ def log(severity, message)
123
+ self.level = DEBUG if $DEBUG
124
+ return unless severity >= level
125
+
126
+ self.warned = true if severity == WARN
127
+ clear_line
128
+ puts "[#{SEVERITIES[severity].to_s.downcase}]: #{message}"
68
129
  end
69
- attr_accessor :warned
70
130
 
71
- # Captures the duration of a block of code for benchmark analysis. Also
72
- # calls {#progress} on the message to display it to the user.
131
+ # @!group Level Control Methods
132
+
133
+ # Sets the logger level for the duration of the block
73
134
  #
74
- # @todo Implement capture storage for reporting of benchmarks
75
- # @param [String] msg the message to display
76
- # @param [Symbol, nil] nontty_log the level to log as if the output
77
- # stream is not a TTY. Use +nil+ for no alternate logging.
78
- # @yield a block of arbitrary code to benchmark
79
- # @return [void]
80
- def capture(msg, nontty_log = :debug)
81
- progress(msg, nontty_log)
135
+ # @example
136
+ # log.enter_level(Logger::ERROR) do
137
+ # YARD.parse_string "def x; end"
138
+ # end
139
+ # @param [Fixnum] new_level the logger level for the duration of the block.
140
+ # values can be found in Ruby's Logger class.
141
+ # @yield the block with the logger temporarily set to +new_level+
142
+ def enter_level(new_level = level)
143
+ old_level = level
144
+ self.level = new_level
82
145
  yield
83
146
  ensure
84
- clear_progress
147
+ self.level = old_level
85
148
  end
86
149
 
150
+ # @!group Utility Printing Methods
151
+
87
152
  # Displays a progress indicator for a given message. This progress report
88
153
  # is only displayed on TTY displays, otherwise the message is passed to
89
154
  # the +nontty_log+ level.
@@ -120,7 +185,7 @@ module YARD
120
185
  # @since 0.8.2
121
186
  def clear_progress
122
187
  return unless show_progress
123
- print_no_newline("\e[?25h\e[2K")
188
+ io.write("\e[?25h\e[2K")
124
189
  @progress_msg = nil
125
190
  end
126
191
 
@@ -133,16 +198,13 @@ module YARD
133
198
  print("#{msg}\n")
134
199
  end
135
200
 
136
- alias print_no_newline <<
137
- private :print_no_newline
138
-
139
201
  # Displays an unformatted line to the logger output stream.
140
202
  # @param [String] msg the message to display
141
203
  # @return [void]
142
204
  # @since 0.8.2
143
205
  def print(msg = '')
144
206
  clear_line
145
- print_no_newline(msg)
207
+ io.write(msg)
146
208
  end
147
209
  alias << print
148
210
 
@@ -158,48 +220,41 @@ module YARD
158
220
  exc.backtrace[0..5].map {|x| "\n\t#{x}" }.join + "\n")
159
221
  end
160
222
 
223
+ # @!group Benchmarking Methods
224
+
225
+ # Captures the duration of a block of code for benchmark analysis. Also
226
+ # calls {#progress} on the message to display it to the user.
227
+ #
228
+ # @todo Implement capture storage for reporting of benchmarks
229
+ # @param [String] msg the message to display
230
+ # @param [Symbol, nil] nontty_log the level to log as if the output
231
+ # stream is not a TTY. Use +nil+ for no alternate logging.
232
+ # @yield a block of arbitrary code to benchmark
233
+ # @return [void]
234
+ def capture(msg, nontty_log = :debug)
235
+ progress(msg, nontty_log)
236
+ yield
237
+ ensure
238
+ clear_progress
239
+ end
240
+
241
+ # @!endgroup
242
+
161
243
  # Warns that the Ruby environment does not support continuations. Applies
162
244
  # to JRuby, Rubinius and MacRuby. This warning will only display once
163
245
  # per Ruby process.
164
246
  #
165
247
  # @deprecated Continuations are no longer needed by YARD 0.8.0+.
166
248
  # @return [void]
249
+ # @private
167
250
  def warn_no_continuations
168
251
  end
169
252
 
170
- # Sets the logger level for the duration of the block
171
- #
172
- # @example
173
- # log.enter_level(Logger::ERROR) do
174
- # YARD.parse_string "def x; end"
175
- # end
176
- # @param [Fixnum] new_level the logger level for the duration of the block.
177
- # values can be found in Ruby's Logger class.
178
- # @yield the block with the logger temporarily set to +new_level+
179
- def enter_level(new_level = level)
180
- old_level = level
181
- self.level = new_level
182
- yield
183
- ensure
184
- self.level = old_level
185
- end
186
-
187
253
  private
188
254
 
189
- # Override this internal Logger method to clear line
190
- def add(*args)
191
- clear_line
192
- super(*args)
193
- end
194
-
195
255
  def clear_line
196
256
  return unless @progress_msg
197
- print_no_newline("\e[2K\r")
198
- end
199
-
200
- # Log format (from Logger implementation). Used by Logger internally
201
- def format_log(sev, _time, _prog, msg)
202
- "[#{sev.downcase}]: #{msg}\n"
257
+ io.write("\e[2K\r")
203
258
  end
204
259
  end
205
260
  end
@@ -0,0 +1,67 @@
1
+ module YARD
2
+ # An OpenStruct compatible struct class that allows for basic access of attributes
3
+ # via +struct.attr_name+ and +struct.attr_name = value+.
4
+ class OpenStruct
5
+ def initialize(hash = {})
6
+ @table = hash.each_pair { |k, v| [k.to_sym, v] }
7
+ end
8
+
9
+ # @private
10
+ def method_missing(name, *args)
11
+ if name.to_s.end_with?('=')
12
+ varname = name.to_s[0..-2].to_sym
13
+ __cache_lookup__(varname)
14
+ send(name, args.first)
15
+ else
16
+ __cache_lookup__(name)
17
+ send(name)
18
+ end
19
+ end
20
+
21
+ def to_h
22
+ @table.dup
23
+ end
24
+
25
+ def ==(other)
26
+ other.is_a?(self.class) && to_h == other.to_h
27
+ end
28
+
29
+ def hash
30
+ @table.hash
31
+ end
32
+
33
+ def dig(*keys)
34
+ @table.dig(*keys)
35
+ end
36
+
37
+ def []=(key, value)
38
+ @table[key.to_sym] = value
39
+ end
40
+
41
+ def [](key)
42
+ @table[key.to_sym]
43
+ end
44
+
45
+ def each_pair(&block)
46
+ @table.each_pair(&block)
47
+ end
48
+
49
+ def marshal_dump
50
+ @table
51
+ end
52
+
53
+ def marshal_load(data)
54
+ @table = data
55
+ end
56
+
57
+ private
58
+
59
+ def __cache_lookup__(name)
60
+ key = name.to_sym.inspect
61
+ instance_eval <<-RUBY, __FILE__, __LINE__ + 1
62
+ def #{name}; @table[#{key}]; end
63
+ def #{name.to_s.sub('?','_')}=(v); @table[#{key}] = v; end unless #{key}.to_s.include?('?')
64
+ RUBY
65
+ end
66
+ end
67
+ end
@@ -656,7 +656,7 @@ module YARD
656
656
  if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
657
657
  (@lex_state != EXPR_ARG || @space_seen)
658
658
  c = peek(0)
659
- tk = identify_here_document if /[-\w\"\'\`]/ =~ c
659
+ tk = identify_here_document if /[-~\w\"\'\`]/ =~ c
660
660
  end
661
661
  if !tk
662
662
  @lex_state = EXPR_BEG
@@ -1063,6 +1063,8 @@ module YARD
1063
1063
  ch = getc
1064
1064
  if ch == "-"
1065
1065
  ch = getc
1066
+ elsif ch == "~"
1067
+ ch = getc
1066
1068
  indent = true
1067
1069
  end
1068
1070
  if /['"`]/ =~ ch # '
@@ -1096,9 +1098,12 @@ module YARD
1096
1098
  str = String.new
1097
1099
  while (l = gets)
1098
1100
  l.chomp!
1099
- l.strip! if indent
1100
- break if l == quoted
1101
- str << l.chomp << "\n"
1101
+ if l == quoted
1102
+ str = dedent(str) if indent
1103
+ break
1104
+ else
1105
+ str << l.chomp << "\n"
1106
+ end
1102
1107
  end
1103
1108
 
1104
1109
  @reader.divert_read_from(reserve)
@@ -1108,6 +1113,16 @@ module YARD
1108
1113
  Token(Ltype2Token[lt], str).set_text(str.dump)
1109
1114
  end
1110
1115
 
1116
+ def dedent(str)
1117
+ lines = str.split("\n", -1)
1118
+ dedent_amt = lines.map do |line|
1119
+ line =~ /\S/ ? line.match(/^ */).offset(0)[1] : nil
1120
+ end.compact.min || 0
1121
+ return str if dedent_amt.zero?
1122
+
1123
+ lines.map { |line| line =~ /\S/ ? line.gsub(/^ {#{dedent_amt}}/, "") : line }.join("\n")
1124
+ end
1125
+
1111
1126
  def identify_quotation(initial_char)
1112
1127
  ch = getc
1113
1128
  if lt = PERCENT_LTYPE[ch]
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require 'stringio'
3
- require 'ostruct'
4
3
 
5
4
  module YARD
6
5
  module Parser
@@ -108,7 +107,8 @@ module YARD
108
107
  files = [paths].flatten.
109
108
  map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
110
109
  map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
111
- reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }
110
+ reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }.
111
+ map {|p| p.encoding == Encoding.default_external ? p : p.dup.force_encoding(Encoding.default_external) }
112
112
 
113
113
  log.enter_level(level) do
114
114
  parse_in_order(*files.uniq)
@@ -143,6 +143,7 @@ module YARD
143
143
  seen_space = false
144
144
  i = 0
145
145
  last_seen = ''
146
+ text ||= ''
146
147
  while i < text.length
147
148
  c = text[i, 1]
148
149
 
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  module Tags
data/lib/yard/tags/tag.rb CHANGED
@@ -23,6 +23,7 @@ module YARD
23
23
  attr_accessor :types
24
24
 
25
25
  # @return [String] a name associated with the tag
26
+ # @return [nil] if no tag name is supplied
26
27
  attr_accessor :name
27
28
 
28
29
  # @return [CodeObjects::Base] the associated object
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  module Templates
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'ostruct'
3
2
 
4
3
  module YARD
5
4
  module Templates
data/lib/yard/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module YARD
5
- VERSION = '0.9.36'
5
+ VERSION = '0.9.37'
6
6
  end
@@ -20,8 +20,8 @@ h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; }
20
20
  #content.insearch #noresults { margin-left: 7px; }
21
21
  li.collapsed ul { display: none; }
22
22
  li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; }
23
- li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; }
24
- li { color: #888; cursor: pointer; }
23
+ li.collapsed a.toggle { cursor: default; background-position: top left; }
24
+ li { color: #666; cursor: pointer; }
25
25
  li.deprecated { text-decoration: line-through; font-style: italic; }
26
26
  li.odd { background: #f0f0f0; }
27
27
  li.even { background: #fafafa; }
@@ -47,7 +47,7 @@ li small { display: block; font-size: 0.8em; }
47
47
  li small:before { content: ""; }
48
48
  li small:after { content: ""; }
49
49
  li small.search_info { display: none; }
50
- #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; }
50
+ #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #666; padding-left: 0; padding-right: 24px; }
51
51
  #content.insearch #search { background-position: center right; }
52
52
  #search input { width: 110px; }
53
53
 
@@ -82,6 +82,11 @@ body {
82
82
  #search { display: none; }
83
83
  }
84
84
 
85
+ @media (max-width: 320px) {
86
+ body { height: 100%; overflow: hidden; overflow-wrap: break-word; }
87
+ #main { height: 100%; overflow: auto; }
88
+ }
89
+
85
90
  #main img { max-width: 100%; }
86
91
  h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; }
87
92
  h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; }
@@ -106,6 +111,7 @@ h2 small a {
106
111
  position: relative;
107
112
  padding: 2px 7px;
108
113
  }
114
+ a { font-weight: 550; }
109
115
  .clear { clear: both; }
110
116
  .inline { display: inline; }
111
117
  .inline p:first-child { display: inline; }
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html <%= "lang=\"#{html_lang}\"" unless html_lang.nil? %>>
3
3
  <head>
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="<%= charset %>" />
@@ -26,7 +26,10 @@
26
26
  <% end %>
27
27
  </div>
28
28
 
29
- <div id="search">Search: <input type="text" /></div>
29
+ <div id="search">
30
+ <label for="search-class">Search:</label>
31
+ <input id="search-class" type="text" />
32
+ </div>
30
33
  </div>
31
34
 
32
35
  <ul id="full_list" class="<%= @list_class || @list_type %>">