Improving MIME type detection for some common file types when they are missing from the system MIME database
Also allow the user to specify their own database via mime.types in the kitty config directory. See #3056
This commit is contained in:
parent
e160cbf32b
commit
75a94bcd96
@ -24,6 +24,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
|||||||
- Fix selections created by dragging upwards not being auto-cleared when
|
- Fix selections created by dragging upwards not being auto-cleared when
|
||||||
screen contents change (:pull:`3028`)
|
screen contents change (:pull:`3028`)
|
||||||
|
|
||||||
|
- Allow adding MIME definitions to kitty by placing a ``mime.types`` file in
|
||||||
|
the kitty config directory (:iss:`3056`)
|
||||||
|
|
||||||
|
|
||||||
0.19.1 [2020-10-06]
|
0.19.1 [2020-10-06]
|
||||||
-------------------
|
-------------------
|
||||||
|
|||||||
@ -81,7 +81,11 @@ lines. The various available criteria are:
|
|||||||
|
|
||||||
``mime``
|
``mime``
|
||||||
A comma separated list of MIME types, for example: ``text/*, image/*,
|
A comma separated list of MIME types, for example: ``text/*, image/*,
|
||||||
application/pdf``
|
application/pdf``. You can add MIME types to kitty by creating the
|
||||||
|
:file:`mime.types` in the kitty configuration directory. Useful if your
|
||||||
|
system MIME database does not have definitions you need. This file is
|
||||||
|
in the standard format of one definition per line, like: ``text/plain rst
|
||||||
|
md``.
|
||||||
|
|
||||||
``ext``
|
``ext``
|
||||||
A comma separated list of file extensions, for example: ``jpeg, tar.gz``
|
A comma separated list of file extensions, for example: ``jpeg, tar.gz``
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import re
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from mimetypes import guess_type
|
from kitty.guess_mime_type import guess_type
|
||||||
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
|
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -136,7 +136,7 @@ def sanitize(text: str) -> str:
|
|||||||
|
|
||||||
@lru_cache(maxsize=1024)
|
@lru_cache(maxsize=1024)
|
||||||
def mime_type_for_path(path: str) -> str:
|
def mime_type_for_path(path: str) -> str:
|
||||||
return guess_type(path)[0] or 'application/octet-stream'
|
return guess_type(path) or 'application/octet-stream'
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1024)
|
@lru_cache(maxsize=1024)
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import mimetypes
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
@ -18,6 +17,7 @@ from typing import (
|
|||||||
Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple, Union
|
Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple, Union
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from kitty.guess_mime_type import guess_type
|
||||||
from kitty.cli import parse_args
|
from kitty.cli import parse_args
|
||||||
from kitty.cli_stub import IcatCLIOptions
|
from kitty.cli_stub import IcatCLIOptions
|
||||||
from kitty.constants import appname
|
from kitty.constants import appname
|
||||||
@ -273,7 +273,7 @@ def process(path: str, args: IcatCLIOptions, parsed_opts: ParsedOpts, is_tempfil
|
|||||||
def scan(d: str) -> Generator[Tuple[str, str], None, None]:
|
def scan(d: str) -> Generator[Tuple[str, str], None, None]:
|
||||||
for dirpath, dirnames, filenames in os.walk(d):
|
for dirpath, dirnames, filenames in os.walk(d):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
mt = mimetypes.guess_type(f)[0]
|
mt = guess_type(f)
|
||||||
if mt and mt.startswith('image/'):
|
if mt and mt.startswith('image/'):
|
||||||
yield os.path.join(dirpath, f), mt
|
yield os.path.join(dirpath, f), mt
|
||||||
|
|
||||||
|
|||||||
@ -394,10 +394,10 @@ def complete_files_and_dirs(
|
|||||||
|
|
||||||
|
|
||||||
def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||||
from mimetypes import guess_type
|
from .guess_mime_type import guess_type
|
||||||
|
|
||||||
def icat_file_predicate(filename: str) -> bool:
|
def icat_file_predicate(filename: str) -> bool:
|
||||||
mt = guess_type(filename)[0]
|
mt = guess_type(filename)
|
||||||
if mt and mt.startswith('image/'):
|
if mt and mt.startswith('image/'):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
45
kitty/guess_mime_type.py
Normal file
45
kitty/guess_mime_type.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import os
|
||||||
|
from contextlib import suppress
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
known_extensions = {
|
||||||
|
'asciidoc': 'text/asciidoctor',
|
||||||
|
'conf': 'text/config',
|
||||||
|
'md': 'text/markdown',
|
||||||
|
'pyj': 'text/rapydscript-ng',
|
||||||
|
'recipe': 'text/python',
|
||||||
|
'rst': 'text/restructured-text',
|
||||||
|
'toml': 'text/toml',
|
||||||
|
'vim': 'text/vim',
|
||||||
|
'yaml': 'text/yaml',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def is_rc_file(path: str) -> bool:
|
||||||
|
name = os.path.basename(path)
|
||||||
|
return '.' not in name and name.endswith('rc')
|
||||||
|
|
||||||
|
|
||||||
|
def guess_type(path: str) -> Optional[str]:
|
||||||
|
if not hasattr(guess_type, 'inited'):
|
||||||
|
setattr(guess_type, 'inited', True)
|
||||||
|
from mimetypes import init
|
||||||
|
init(None)
|
||||||
|
from kitty.constants import config_dir
|
||||||
|
local_defs = os.path.join(config_dir, 'mime.types')
|
||||||
|
if os.path.exists(local_defs):
|
||||||
|
init((local_defs,))
|
||||||
|
from mimetypes import guess_type as stdlib_guess_type
|
||||||
|
mt = None
|
||||||
|
with suppress(Exception):
|
||||||
|
mt = stdlib_guess_type(path)[0]
|
||||||
|
if not mt:
|
||||||
|
ext = path.rpartition('.')[-1].lower()
|
||||||
|
mt = known_extensions.get(ext)
|
||||||
|
if not mt and is_rc_file(path):
|
||||||
|
mt = 'text/plain'
|
||||||
|
return mt
|
||||||
@ -17,6 +17,7 @@ from .config import KeyAction, parse_key_action
|
|||||||
from .constants import config_dir
|
from .constants import config_dir
|
||||||
from .typing import MatchType
|
from .typing import MatchType
|
||||||
from .utils import expandvars, log_error
|
from .utils import expandvars, log_error
|
||||||
|
from .guess_mime_type import guess_type
|
||||||
|
|
||||||
|
|
||||||
class MatchCriteria(NamedTuple):
|
class MatchCriteria(NamedTuple):
|
||||||
@ -75,12 +76,8 @@ def url_matches_criterion(purl: 'ParseResult', url: str, unquoted_path: str, mc:
|
|||||||
|
|
||||||
if mc.type == 'mime':
|
if mc.type == 'mime':
|
||||||
import fnmatch
|
import fnmatch
|
||||||
from mimetypes import guess_type
|
mt = guess_type(unquoted_path)
|
||||||
try:
|
if not mt:
|
||||||
mt = guess_type(unquoted_path)[0]
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
if mt is None:
|
|
||||||
return False
|
return False
|
||||||
mt = mt.lower()
|
mt = mt.lower()
|
||||||
for mpat in mc.value.split(','):
|
for mpat in mc.value.split(','):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user